首页 > 编程语言 >java多线程2

java多线程2

时间:2022-08-28 23:16:03浏览次数:55  
标签:同步 java Thread synchronized 线程 多线程 方法 public

我们知道,线程有五种生命周期:新建,就绪,运行,阻塞,死亡.

在我们编写,运行代码的过程中,可能出现线程死锁,线程阻塞等问题,下面介绍线程产生这些问题的原因,及解决的方案,保证线程能正常运行.

一、线程阻塞

线程阻塞的原因

1.调用sleep(),让线程变为睡眠状态,但是手里还拿着这个资源不放,后面的线程一直等待它醒来,然后等待它执行完,才能轮到下一个线程
2.调用join()方法,相当于插队,等插入的新线程执行完,再执行回原来的线程
3.调用wait()方法,进入等待状态,把CPU交出去,然后"睡去",但是该线程不会自然醒,需要用notify()方法唤醒
4.调用yield()方法,释放资源,然后与其他线程一起抢该资源

二、线程的终止

在java中,我们不采用stop()方法来终止线程,若是使用stop方法终止线程,会使得输出的信息破坏或者不完整,而且破坏了原子性的操作.

如何让线程终止,下面介绍两种常用的方法

1.通过给定属性,然后通过控制属性值来破坏继续执行的条件

private boolean flag = true;//属性

//线程实现Runnable接口,重写run方法
@Override
    public void run() {
        int i = 0;
        //通过flag来控制循环
        while (flag) {
            System.out.println("执行线程_" + i);
            i++;
        }
    }  
//在实现方法中,若要想结束, flag = false;

2.使用interrupt()方法在线程阻塞状态下结束线程。

public class MyRun implements Runnable {
    @Override
    public void run() {
        int i = 0;
        while(true){
            System.out.println("线程_"+i);
            i++;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                break;
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyRun mr = new MyRun();
        Thread th = new Thread(mr);
        th.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //使用interrupt()方法结束该线程
        th.interrupt();
    }
}

三、线程同步

在java中,通过关键字synchronized给对象加互斥锁,达到多个线程共享数据的操作,叫做线程同步.

1.同步代码块

synchronized放在对象前面限制一段代码的执行

Object obj = new Object();
...
synchronized(this){//this被加锁,任何其他要锁this的方法和代码块被阻塞.
 需要同步的代码;
}
...
synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.
 需要同步的代码;
}

2.同步方法

同步非静态方法:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象,如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后

public synchronized void method(){
 …
}

同步static方法: synchronized放在static方法声明中,表示锁定该类的class对象,如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响

public synchronized static void method(){
 …
}

四、线程死锁

 1.产生死锁的原因

​    1> 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

​    2> 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

​    3> 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占用。

​    4> 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路

2.解决方法

在我们的项目中,为了避免死锁,以上四个条件,破坏其中任意一个,死锁就结束了

下面通过破坏请求和保持条件,通过获得-释放资源的方式,让每个线程都能拥有过资源

//解决死锁
public class MyRun implements Runnable{
    Object a = new Object();
    Object b = new Object();

    @Override
    public void run() {
        synchronized (a){
            System.out.println(Thread.currentThread().getName()+"获得了a资源");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"释放了a资源");
        }
        synchronized (b){
            System.out.println(Thread.currentThread().getName()+"获得了b资源");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"释放了b资源");
        }
    }

    public static void main(String[] args) {
        MyRun myRun = new MyRun();
        Thread t1 = new Thread(myRun,"线程1");
        Thread t2 = new Thread(myRun,"线程2");
        t1.start();
        t2.start();
    }
}

五、总结

1.过多的同步会导致死锁

2.synchronized修饰静态方法,如果调用该方法,将会锁住整个类

3.synchronized不能被抽象类里的抽象方法,和接口中的方法使用,synchronized修饰的方法,可以是静态,也可以是非静态

4.当任意一个线程进入到一个对象中的任意一个同步方法时,这个对象的所有同步方法都被锁定了

5.两个被synchronized修饰过的方法,静态同步方法一起执行:锁的是类.class ,不需要等待;非静态同步方法:锁的是this,需要等待上一个释放

 

标签:同步,java,Thread,synchronized,线程,多线程,方法,public
From: https://www.cnblogs.com/pilpill/p/16633649.html

相关文章

  • JavaFX
    什么是JavaFX?1.JavaFX是基于java语言的图形化界面工具箱,带有大量的内置组件,如按钮,文本字段,表格,树,菜单,图表等2.JavaFX支持2D图形、3D图形、WebView3.JavaFX编写的程......
  • 求助:在IDEA中,有关Java异常打印输出中文问题?
    importjava.io.FileInputStream;importjava.io.FileNotFoundException;publicclassExceptionTest00{publicstaticvoidmain(String[]args){try{......
  • JavaScript--关于this
    一、为什么会有this的出现  “this关键词是JS中最复杂的机制之一,它是一个很特别的关键字,被自动定义在所有函数的作用域中”根据凯尔辛普森的书中描述,刚开始阅读时我对......
  • leetcode 斐波那契数列 javascript实现
    写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项(即F(N))。斐波那契数列的定义如下:F(0)=0,  F(1) =1F(N)=F(N-1)+F(N-2),其中N>1.斐波那契数列由0......
  • 利用Java集合实现学生信息的”增删查“
    之前学了Java中的集合,打算写一个小程序来消化一下!那么我们知道,集合相比数组的优点就是可以动态的增加元素,这对比数组来说,十分的便捷;并且集合为我们封装好一些方法,可以更......
  • 100套计算机专业java毕设项目
    100套java开学内卷项目论文源码随你挑今天分享100套计算机Java设计项目,可练手又可当毕设,而且包含了参考论文文档资料;有需要的可以翻翻看    源码获取百度网盘:......
  • 做自动化测试选择Python还是Java?
    你好,我是测试蔡坨坨。今天,我们来聊一聊测试人员想要进阶,想要做自动化测试,甚至测试开发,如何选择编程语言。前言自动化测试,这几年行业内的热词,也是测试人员进阶的必备技能......
  • java 实现字符串转换为树
    importjava.util.*;classNode{publicstaticvoidmain(String[]args){ArrayList<String>listOfPaths=newArrayList<String>();l......
  • JavaScript的函数
    //alert是JavaScript语言提供的一个警告函数//它可以接收任意类型的参数,这个参数就是警告框的提示信息   <!DOCTYPEhtml><htmllang="en"><head><metacharse......
  • 力扣393(java)-UTF-8编码验证(中等)
    题目:给定一个表示数据的整数数组 data ,返回它是否为有效的UTF-8编码。UTF-8中的一个字符可能的长度为1到4字节,遵循以下的规则:对于1字节 的字符,字节的第一位......