博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 线程同步方式
阅读量:6344 次
发布时间:2019-06-22

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

相关连接: 

相关概念:

1,独占资源和共享资源。这里说的独占和共享,是指是否只有一个线程可以占有这个锁。独占并不是说这个资源只可以lock一次,有可能一个线程可以lock多次,这被叫做可重入。

2.,公平、非公平。一个锁资源是否应该按照线程申请的先后顺序分配,还是允许后申请的线程先获得锁。前者是公平锁,后者叫非公平锁。

3,并发相关的三原则:原子性、可见性、有序性。原子性指一组操作不可分割,要么执行,要么不执行。计算机的rom分高速缓存和主存。Java中线程会有一个工作内存,当变量的值被修改的时候,可能只写入了线程相关的高速缓存,而没有写去主存。这种情况下,其他线程读取不到正确的数值。这样的现象成为变量不可见。有序性是关于Java指令重排的。Java的指令重排可能会引发多线程数据异常,例如 一个 初始化操作在状态变量标记为完成后才执行。

 

volatile 修饰的变量具有可见性,它的修改会被直接写入主存。 java指令重排的时候不会重排volatile语句,写在volatile语句(读或写)之前的语句一定在volatile语句之前执行,写在之后的一定在volatile语句之后执行。

volatile应用场景,标记状态量,double check

 

公平锁举例:new ReentrantLock(true)

非公平锁举例:new ReentrantLock(false)、synchronized

独享锁举例:ReentrantLock、synchronized 

 

注意点:资源的释放需要在finally语句中进行。

 

Java中synchronized关键字锁定的是对象。验证代码如下:

class Demo{    public synchronized void  sayHello(){        try{            System.out.println("hello start");            Thread.sleep(100);            System.out.println("hello end");        }catch (InterruptedException e){            e.printStackTrace();        }    }    public synchronized void doAction()    {        try{            System.out.println("put up hand");            Thread.sleep(100);            System.out.println("put down hand");        }catch (InterruptedException e){            e.printStackTrace();        }    }}public class Test {    public static void main(String[] args)    {        Demo demo = new Demo();        Demo demoA = new Demo();        Thread sayThread = new Thread(new Runnable() {            @Override            public void run() {                demo.sayHello();            }        });        Thread actionThread = new Thread(new Runnable() {            @Override            public void run() {//                demo.doAction();                demoA.doAction();            }        });        sayThread.start();        actionThread.start();    }}

三种情况:

1、两个线程都使用demo变量,方法用synchronized修饰。 结果: sayHello和doAction一定是一个执行完另一个才执行。

2,两个线程都使用demo变量,方法不使用synchronized修饰。结果:sayHello和doAction可以交叉执行。

3、两个线程分别使用demo和demoA变量,方法用synchronized修饰。 结果: sayHello和doAction可以交叉执行。

 synchronized 和 static 同时修饰一个方法

class Worker{    public static synchronized void doWork(String name)    {        try {            System.out.println(name+ " starts a work");            Thread.sleep(100);            System.out.println(name+ " finish a work");        }catch (InterruptedException e)        {            e.printStackTrace();        }    }}public class Test {    public static void main(String[]args)    {        Thread threadA = new Thread(new Runnable() {            @Override            public void run() {                new Worker().doWork("zhangsan");            }        });        Thread threadB = new Thread(new Runnable() {            @Override            public void run() {                new Worker().doWork("lisi");            }        });        threadA.start();        threadB.start();    }}

  

Semaphore 用法:

import java.util.concurrent.Semaphore;class PreTask implements Runnable{    private Semaphore sem;    private int weight;    PreTask(Semaphore sem, int weight){        this.sem = sem;        this.weight = weight;    }    public void run()    {        try{            System.out.println("a pretask starts");            Thread.sleep(100);            System.out.println("a pretask is done which weight is "+this.weight);                    }catch (InterruptedException e){            e.printStackTrace();        }finally{
// 在finally中释放资源
this.sem.release(this.weight); }
} } class LateTask implements Runnable { private Semaphore sem; private int requireWeight; LateTask(Semaphore sem, int requireWeight) { this.sem = sem; this.requireWeight = requireWeight; } public void run() { try{ this.sem.acquire(this.requireWeight); System.out.println("a latetask starts"); Thread.sleep(100); System.out.println("a latetask is done which requireWeight is "+this.requireWeight); }catch (InterruptedException e){ e.printStackTrace(); } } } public class Test { public static void main(String[] args) { Semaphore semaphore = new Semaphore(0); PreTask preA = new PreTask(semaphore, 1); PreTask preB = new PreTask(semaphore, 3); LateTask late = new LateTask(semaphore, 4); Thread preThreadA = new Thread(preA); Thread preThreadB = new Thread(preB); Thread lateThreadB = new Thread(late); preThreadA.start(); preThreadB.start(); lateThreadB.start(); } }

 输出结果如下:

a pretask starts

a pretask starts
a pretask is done which weight is 3
a pretask is done which weight is 1
a latetask starts
a latetask is done which requireWeight is 4

import java.util.concurrent.Semaphore;class User implements Runnable{    private Semaphore sem;    private String name;    User(Semaphore sem, String name){        this.sem = sem;        this.name = name;    }    public void run()    {        try{            this.sem.acquire(1);            System.out.println(this.name+" take up a pen");            Thread.sleep(100);            System.out.println(this.name+" put down a pen ");                    }catch (InterruptedException e){            e.printStackTrace();        }finally{
//在finally中释放资源
this.sem.release(1);
}    }}public class Test {    public static void main(String[] args)    {        Semaphore penSet = new Semaphore(2);        User zhangsan = new User(penSet, "zhangsan");        User lisi = new User(penSet, "lisi");        User wangwu = new User(penSet, "wangwu");        User zhaoliu = new User(penSet, "zhaoliu");        Thread threadZhangsan = new Thread(zhangsan);        Thread threadL = new Thread(lisi);        Thread threadW = new Thread(wangwu);        Thread threadZhaoliu = new Thread(zhaoliu);        threadZhangsan.start();        threadL.start();        threadW.start();        threadZhaoliu.start();    }}

 结果:最多同时有两个人在使用铅笔

 Semaphore tryAquire,尝试获取一个数量的资源,这个方法是非阻塞的,返回一个boolean值表示是否获得了资源。

import java.util.concurrent.Semaphore;class Worker{    public void doWork(Semaphore tool, String name)    {        if (tool.tryAcquire(1))        {            try {                System.out.println(name+ " starts a work with tool");                Thread.sleep(100);                System.out.println(name+ " finish a work and release tool");            }catch (InterruptedException e)            {                e.printStackTrace();            }finally {                tool.release();            }        }else        {            try {                System.out.println(name+ " starts a work with hand");                Thread.sleep(500);                System.out.println(name+ " finish a work ");            }catch (InterruptedException e)            {                e.printStackTrace();            }finally {            }        }    }}public class Test {    public static void main(String[]args)    {        Semaphore tool = new Semaphore(1);        Thread threadA = new Thread(new Runnable() {            @Override            public void run() {                new Worker().doWork(tool,"zhangsan");            }        });        Thread threadB = new Thread(new Runnable() {            @Override            public void run() {                new Worker().doWork(tool,"lisi");            }        });        threadA.start();        threadB.start();    }}

  

两个人可以同时工作,但同一时间只有一个人使用工具工作,另一个人只能用手。

结果如下:

lisi starts a work with hand

zhangsan starts a work with tool
zhangsan finish a work and release tool
lisi finish a work

 

Java中的volatile关键字说,保证对变量的修改直接写入主存,线程读取变量的时候不会受到线程缓存的影响。轮询语句的条件变量就适合使用volatile关键字修饰    while( ! stop){}。 

volatile并不保证关于变量的操作是原子性的。i++不具有原子性,AtomicInteger 提供了原子操作。

import java.util.ArrayList;import java.util.concurrent.Semaphore;import java.util.concurrent.atomic.AtomicInteger;class Room{    //    public static volatile int personCount = 0;    public static AtomicInteger inc = new AtomicInteger(0);    public static void personEnter()    {        try{            Thread.sleep(100);        }catch (InterruptedException e){        }finally {        }//        Room.personCount = Room.personCount+1;        inc.getAndIncrement();    }}public class Test {    public static void main(String[]args)    {        ArrayList
threadList = new ArrayList(10); for(int i=0; i< 10; i++){ Thread thread = new Thread(new Runnable() { @Override public void run() { Room.personEnter(); } }); threadList.add(thread); } for (int i =0;i
2) Thread.yield(); System.out.println(Room.inc); }}

  

使用volatile的结果是小于等于10的数,使用AtomicInteger结果一定是10

 

ReentrantLock 可重入锁,可重入是针对线程而言的。

import java.util.concurrent.locks.ReentrantLock;class Door implements Runnable{    private ReentrantLock reentrantLock;    private String name;    public Door(ReentrantLock reentrantLock,String name)    {        this.reentrantLock = reentrantLock;        this.name = name;    }    @Override    public void run() {        try{            Thread.sleep(0);        }catch (InterruptedException e){        }finally {        }        this.reentrantLock.lock();        System.out.println(this.name+" lock once");        this.reentrantLock.lock();        try{            Thread.sleep(0);        }catch (InterruptedException e){        }finally {        }        System.out.println(this.name+" lock twice");        System.out.println(this.name+" will unlock once");        this.reentrantLock.unlock();        System.out.println(this.name+" will unlock twice");        this.reentrantLock.unlock();    }}public class Test {    public static void main(String[]args)    {        ReentrantLock reentrantLock = new ReentrantLock();        Thread blackThread = new Thread(new Door(reentrantLock, "blackDoor"));        Thread whiteThread = new Thread(new Door(reentrantLock, "whiteDoor"));        blackThread.start();        whiteThread.start();    }}

 结果:

blackDoor lock once

blackDoor lock twice
blackDoor will unlock once
blackDoor will unlock twice
whiteDoor lock once
whiteDoor lock twice
whiteDoor will unlock once
whiteDoor will unlock twice

转载于:https://www.cnblogs.com/afraidToForget/p/10117340.html

你可能感兴趣的文章
YourSQLDba 配置——修改备份路径
查看>>
nginx web服务理论与实战
查看>>
java 库存 进销存 商户 多用户管理系统 SSM springmvc 项目源码
查看>>
网易音乐版轮播-react组件版本
查看>>
ES6 - 函数与剩余运算符
查看>>
你对position了解有多深?看完这2道有意思的题你就有底了...
查看>>
WebSocket跨域问题解决
查看>>
ECMAScript6基本介绍
查看>>
世界经济论坛发布关于区块链网络安全的报告
查看>>
巨杉数据库加入CNCF云原生应用计算基金会,共建开源技术生态
查看>>
Ubuntu 16.04安装Nginx
查看>>
从 JS 编译原理到作用域(链)及闭包
查看>>
flutter 教程(一)flutter介绍
查看>>
CSS面试题目及答案
查看>>
【从蛋壳到满天飞】JS 数据结构解析和算法实现-Arrays(数组)
查看>>
每周记录(三)
查看>>
Spring自定义注解从入门到精通
查看>>
笔记本触摸板滑动事件导致连滑的解决方式
查看>>
Runtime 学习:消息传递
查看>>
你了解BFC吗?
查看>>