Java多线程:


学习内容:

  1. 多线程概念
  2. Java实现多线程
  3. 并发中的同步机制
  4. 案例:多线程实现死锁
  5. 补充

1.多线程概念:

线程是操作系统进行资源分配的基本单位。例如使用QQ时,可以在视频电话的同时发送信息。QQ是一个进程,该进程中的视频电话的程序运行是进程中的一个线程,该进程中的发送信息也是进程中的一个线程。
因此,线程很重要。如果一个进程只有单线程,单线程内有下载任务,只有等下载完成后,该线程才能继续往下走。

2.Java实现多线程:

两种方法
(1)Java实现多线程可以通过继承Threa类,并重写Run方法(2)实现Runnable接口,并重写Run方法第一种:继承Thread类

public class testThread extends Thread {
    @Override
    public void run() {
        for (int i=0;i<20;i++){
            System.out.println("新建线程执行"+i);
        }
    }

    public static void main(String[] args) {
        testThread testThread=new testThread();
        testThread.start();
        for (int i=0;i<20;i++){
            System.out.println("主线程执行"+i);
        }
    }
}

运行结果

java多线程怎么写 java 多线程的使用_java


主线程并没有等待新建的线程完成之后再执行for循环,两个线程是在同时运行的。

第二种:实现Runnable接口

public class testRunable implements Runnable {
    @Override
    public void run() {
        for (int i=0;i<20;i++){
            System.out.println("新建线程执行"+i);
        }
    }

    public static void main(String[] args) {
        testRunable testRunable=new testRunable();
        Thread thread=new Thread(testRunable);
        thread.start();
        for (int i=0;i<20;i++){
            System.out.println("主线程执行"+i);
        }
    }
}

3.并发中的同步机制:

多线程存在的问题:多线程操作共享资源时不安全。例如一个进程中的两个线程都是购买火车票的线程,第一个线程看到还有一张票,准备执行下一句代码,此时第二个线程同样看到还有一张票,也准备执行下一句代码。两个线程都执行票数减一操作,最后票数成为-1。
解决问题:对于共享资源,使用synchronized对共享资源上锁,简单来说就是实现同步操作。对于上面的例子,将检查票数和票数减一上个锁,当一个线程进入检查票数后,其他线程不能进入检查票数。

同步的实现代码

public class testSynchronized  implements Runnable {
    private static int tickerNums=200;
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }//让线程沉睡一会,能够放大多线程的效果

            //将检查票数和票数减一上锁,该操作一气呵成,所有线程共享static变量tickerNums
            synchronized ((Object) tickerNums){
                if(tickerNums<=0) {
                    System.out.println("没票了");
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"->抢到了票"+tickerNums--);
            }
        }
    }

    public static void main(String[] args) {
        testRunable testRunable=new testRunable();
        new Thread(testRunable,"A").start();//新建一个A线程
        new Thread(testRunable,"B").start();//新建一个B线程
        new Thread(testRunable,"C").start();//新建一个C线程
    }
}

同步结果

java多线程怎么写 java 多线程的使用_java多线程怎么写_02

异步结果

java多线程怎么写 java 多线程的使用_开发语言_03

对于C线程,已经将票数减为1,但对于A线程,仍然以为票数为12,所以进行了抢票。

Synchronized也可以用在方法上,即多个线程调用方法时必须按顺序调用,不过容易导致把不需要同步的代码同步了,降低效率。

4.多线程实现死锁:

开两个线程,设置一个共享资源,使两个线程呈现请求并占有,互相等待的状态

public class lock implements Runnable{
    private static int num=1000;//总资源数 总共1000个资源,假如每个线程需要500个才能结束
    private static int cnt=100;//控制等待资源输出次数
    private int mynum=0;//获得资源数
    @Override
    public void run() {
        //一共1000个资源,只有等线程获取900个资源时才退出,两个线程一般情况下会是一个线程七八百资源,一个两三百资源,然后互相等待并请求保持
        while(true){
            if(num<=0&&mynum!=900){
                synchronized((Object)num){
                    cnt--;
                    if(cnt<=0) break;
                }
                System.out.println(Thread.currentThread().getName()+"正在等待资源");
            }
            else if(num>0&&mynum!=900){
                synchronized((Object)num){
                    System.out.println(Thread.currentThread().getName()+"获取了资源,目前资源数"+mynum);
                    mynum++;
                    num--;
                }
            }
            else if(mynum==900){
                synchronized((Object)num){
                    System.out.println("资源足够,释放资源");
                    num+=2;
                    break;
                }
            }
        }
    }
    public static void main(String[] args) {
        new Thread(new lock(),"A").start();
        new Thread(new lock(),"B").start();
    }

}

运行结果

java多线程怎么写 java 多线程的使用_System_04

5.补充:

(1)lamda表达式

public class testLamda {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println("新建线程输出");
        }).start();
        System.out.println("主线程输出");
    }
}

()->{},这句话表示了实现Run方法,实现代码为花括号里的代码。()代表实现的函数,传参为空。

使用条件:只适用于接口,接口只有一个方法。

好处:核心代码直接展示,代码简洁。

(2)Thread方法(转自菜鸟教程)

java多线程怎么写 java 多线程的使用_System_05


(3)守护线程

A线程守护B线程。B线程结束后,A线程结束。

实现过程

新建A、B线程。

主函数内:

A线程setDaemon(true),.

A、B线程调用Start启动。