1、多线程共享数据
在多线程的操作中,多个线程有可能同时处理同一一个资源,这就是多线程中的共享数据。
2、线程同步
解决数据共享问题,必须使用同步,所谓同步就是指多个线程在同一个时间段内只能有一一个线程执行指定代码,
其他线程要等待此线程完成之后才可以继续执行。
线程进行同步,有以下三种方法:
(1)同步代码块
synchronized(要同步的对象){
要同步的操作;
(2)同步方法
public synchronized void method(){
要同步的操作;
(3) Lock ( ReentrantLock)
3、同步准则
当编写synchronized块时,有几个简单的准则可以遵循,这些准则在避免死锁和性能危险的风险方面大有帮助:
(1)使代码块保持简短。把不随线程变化的预处理和后处理移出synchronized块。
(2)不要阻塞。如InputStream.read()。
(3)在持有锁的时候,不要对其它加了同步锁对象调用方法。
多线程共享数据,会有安全问题,使用同步能解决安全问题,但同时会牺牲性能,因此同步代码块要尽量简短,把不随数据变化的相关代码移除代码块,同时也要注意不要阻塞。
死锁
过多的同步有可能出现死锁,死锁的操作-般是在程序运行的时候才 有可能出现。
多线程中要进行资源的共享,就需要同步,但同步过多,就可能造成死锁。在实际中应该避免死锁的产生。
同步锁代码示例
package com.booy;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo3 {
public static void main(String[] args) {
MyRunnable4 mr4 = new MyRunnable4();
Thread t = new Thread(mr4);
Thread t1 = new Thread(mr4);
t.start();
t1.start();
}
}
class MyRunnable4 implements Runnable{
private int ticket=10;
private Object obg = new Object();
@Override
public void run() {
for (int i = 0; i <300 ; i++) {
/* if(ticket>0){
//方法1:同步代码块加同步锁
synchronized (obg){
ticket--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("你购买的票剩余:"+ticket+"张");
}
}*/
method2();
}
}
//方法2:同步方法加同步锁
public synchronized void method(){
if(ticket>0){
ticket--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("你购买的票剩余:"+ticket+"张");
}
}
//互斥锁
ReentrantLock rt = new ReentrantLock();
//方法3:Lock锁
public void method2(){
rt.lock();//加锁
if(ticket>0){
ticket--;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("你购买的票剩余:"+ticket+"张");
}
rt.unlock();//释放锁
}
}
/**
运行结果:
你购买的票剩余:9张
你购买的票剩余:8张
你购买的票剩余:7张
你购买的票剩余:6张
你购买的票剩余:5张
你购买的票剩余:4张
你购买的票剩余:3张
你购买的票剩余:2张
你购买的票剩余:1张
你购买的票剩余:0张
*/