博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java多线程-线程的同步
阅读量:2169 次
发布时间:2019-05-01

本文共 4513 字,大约阅读时间需要 15 分钟。

在java中要实现多线程之间的同步操作主要有如下两种方式:synchronized关键字和对象的wait()和notify()/notifyAll();

首先来看一下synchronized关键的字的使用

作用范围:

  1. 给指定对象加锁,在进入同步代码块前需要先获得指定对象的锁
package com.ziwu.learn.thread;public class TestLock implements  Runnable{    private Object object = new Object();    private static int i=0;    @Override    public void run() {        synchronized (object){            increments();        }    }    private void increments() {        for(int j = 0;j < 1000000;j++){            i++;        }    }    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(new TestLock());        Thread t2 = new Thread(new TestLock());        t1.start();t2.start();        t1.join();        t2.join();        System.out.println(i);    }}

     因为object属于当前实例的,所以每个线程都有各自的锁,所有存在线程安全问题,结果小于2000万。

     2.作用于实例方法,相当于对当前实例加锁,在进入同步代码块前需要先获得当前实例对象的锁

    

package com.ziwu.learn.thread;public class TestLock implements  Runnable{    private static int i=0;    @Override    public void run() {        increments();    }    private synchronized void increments() {        for(int j = 0;j < 1000000;j++){            i++;        }    }    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(new TestLock());        Thread t2 = new Thread(new TestLock());        t1.start();t2.start();        t1.join();        t2.join();        System.out.println(i);    }}

     synchronized用于实例方法上,相当于给当前实例加锁,所以两个线程拥有不同的锁,故而不是线程安全的。

3.作用于静态方法,相当于给当前类加锁,进入同步代码前要获得当前类的锁

package com.ziwu.learn.thread;public class TestLock implements  Runnable{    private static int i=0;    @Override    public void run() {        increments();    }    private static synchronized void increments() {        for(int j = 0;j < 1000000;j++){            i++;        }    }    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(new TestLock());        Thread t2 = new Thread(new TestLock());        t1.start();t2.start();        t1.join();        t2.join();        System.out.println(i);    }}

这段代码的输出结果是正常的,因为静态方法是属于类的,所以相当于两个线程公用一把锁,所以是线程安全的。

看到这里如何将1.1和1.2的方法变成线程安全的那么就很容易了,核心就是让当前两个线程采用一个锁或者将方法声明为static的使用类锁。

package com.ziwu.learn.thread;public class TestLock implements  Runnable{    private static int i=0;    @Override    public void run() {        increments();    }    private  synchronized void increments() {        for(int j = 0;j < 1000000;j++){            i++;        }    }    public static void main(String[] args) throws InterruptedException {        TestLock test = new TestLock();        Thread t1 = new Thread(test);        Thread t2 = new Thread(test);        t1.start();t2.start();        t1.join();        t2.join();        System.out.println(i);    }}

后面来看一个使用Object.wait(),和Object.notify()让线程协同执行,相比加锁,Object的wait和notify使得个线程可以有序调度。

这两个方法都会抛出 IllegalMonitorStateException异常,需要注意的是wait方法会释放监视器锁,大致语义是是在调用方法的时候没有获取到监视器锁就会异常,简而言之就是该方法得配合synchronized使用,

package com.ziwu.learn.thread;public class TestWait {    private  static  final  Object object = new Object();    static  class T1 implements  Runnable{        @Override        public void run() {            synchronized (object){                System.out.println("t1 is start");                try {                    System.out.println("t1 is start wait");                    object.wait();                    System.out.println("t1 is end wait");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    static  class T2 implements  Runnable{        @Override        public void run() {            synchronized (object){                System.out.println("t2 is start");                try {                    Thread.sleep(5000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("t2 is start notify");                object.notify();                try {                    Thread.sleep(5000);                    System.out.println("t2 is end notify");                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) {        Thread t1 = new Thread(new T1());        Thread t2 = new Thread(new T2());        t1.start();        t2.start();    }}

该段代码的输出:

t1 is start

t1 is start wait
t2 is start
t2 is start notify
t2 is end notify
t1 is end wait‘

可以看到t2在唤醒线程t1后,t1并没有立刻执行因为t2还没有执行完成,故而监视器锁还没有释放,t1此时是拿不到锁的。

转载地址:http://xhazb.baihongyu.com/

你可能感兴趣的文章
HTM+CSS实现立方体图片旋转展示效果
查看>>
FFmpeg 命令操作音视频
查看>>
问题:Opencv(3.1.0/3.4)找不到 /opencv2/gpu/gpu.hpp 问题
查看>>
目的:使用CUDA环境变量CUDA_VISIBLE_DEVICES来限定CUDA程序所能使用的GPU设备
查看>>
问题:Mysql中字段类型为text的值, java使用selectByExample查询为null
查看>>
程序员--学习之路--技巧
查看>>
解决问题之 MySQL慢查询日志设置
查看>>
contOS6 部署 lnmp、FTP、composer、ThinkPHP5、docker详细步骤
查看>>
TP5.1模板布局中遇到的坑,配置完不生效解决办法
查看>>
PHPstudy中遇到的坑No input file specified,以及传到linux环境下遇到的坑,模板文件不存在
查看>>
TP5.1事务操作和TP5事务回滚操作多表
查看>>
composer install或composer update 或 composer require phpoffice/phpexcel 失败解决办法
查看>>
TP5.1项目从windows的Apache服务迁移到linux的Nginx服务需要注意几点。
查看>>
win10安装软件 打开时报错 找不到 msvcp120.dll
查看>>
PHPunit+Xdebug代码覆盖率以及遇到的问题汇总
查看>>
PHPUnit安装及使用
查看>>
PHP项目用xhprof性能分析(安装及应用实例)
查看>>
composer安装YII
查看>>
Sublime text3快捷键演示
查看>>
sublime text3 快捷键修改
查看>>