线程同步
package com.vince;
import java.util.concurrent.locks.ReentrantLock;
/**
* 1、多线程共享数据时,会发生线程不安全的情况
* 2、多线程共享数据必须使用同步
* 3、实现同步的三种方法:
* (1)使用同步代码块;
* (2)使用同步方法;
* (3)使用Lock(更灵活的代码控制)
* 同步线程的准则:
* 1、多线程共享数据,会有安全问题,使用同步可以解决安全问题,但同时会牺牲性能,所以同步的代码块要尽量保持简短,把不随数据变化的相关代码移除同步块。
* 2、不要阻塞。 如InputStream.read()
* 3、在持有锁的时候,不要对其它对象调用它的同步方法,防止死锁的出现。
*
*/
public class ThreadDemo4 {
public static void main(String[] args){
MyRunnable6 mr = new MyRunnable6();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.start();
t2.start();
}
}
class MyRunnable6 implements Runnable{
private int ticket=10;
/**
* 不加线程同步,即线程是不安全的:得出的结果有可能会是如下
* 剩余票数是:8张
* 剩余票数是:8张
* 剩余票数是:6张
* 剩余票数是:5张
* 剩余票数是:4张
* 剩余票数是:4张
* 剩余票数是:2张
* 剩余票数是:2张
* 剩余票数是:0张
* 剩余票数是:0张
*/
@Override
public void run() {
for(int i=0;i<30;i++){
if(ticket>0){
ticket--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余票数是:"+ticket+"张");
}
}
}
//线程同步三种方法:
/**
* 方法1:
* synchronized(要同步的对象){
* 要同步的操作;
* }
*/
Object obj = new Object();
@Override
public void run() {
for(int i=0; i<30; i++){
synchronized (obj) { // 同步锁,一般使用synchronized (this),this表示当前对象,即实现了是同一个对象
if(ticket>0) {
ticket--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余票数是:" + ticket + "张");
}
}
}
}
/**
* 方法2:
* 创建同步方法
* public synchronized void method(){
* 要同步的操作;
* }
*/
public void run(){
for (int i = 0; i <300 ; i++) {
method();
}
}
//同步方法,同步的是当前对象this
public synchronized void method(){
if(ticket>0){
ticket--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余票数是:" + ticket + "张");
}
}
/**
* 方法3:
* 创建Lock对象,Lock是一个接口
* ReentrantLock lock = new ReentrantLock();
* lock.lock(); 锁住线程
* lock.unlock(); 解锁线程
* 因此:此方法的优点是可灵活控制线程锁的启动和关闭
*/
public void run(){
for (int i=0;i<300;i++){
method();
}
}
ReentrantLock lock = new ReentrantLock(); //互斥锁
public void method(){
lock.lock(); //锁住线程
try{
if(ticket>0){
ticket--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("剩余票数是:" + ticket + "张");
}
}finally {
lock.unlock(); //解锁线程:为了确保一定能解锁防止死锁,一般可写成try...finally{里解锁线程},这样就能保证解锁的代码一定能执行到
}
}
}