java线程同步
转自:战国剑的博客,网址:http://blog.****.net/yangzhaomuma/article/details/51236976
其中,图中标红的方法已经过时。
(1)join方法,主要作用是在该线程中的run方法结束后,才能向下执行。如:
package threadTest;
public class ThreadJoin {
public static void main(String[] args) {
Thread thread= new Thread(new Runnable() {
@Override
public void run() {
System.err.println("线程"+Thread.currentThread().getId()+" 打印信息");
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.err.println("主线程打印信息");
}
}
//如果有 thread.join(); ,则会先运行run方法的 System.err.println("线程"+Thread.currentThread().getId()+" 打印信息"); ,之后运行System.err.println("主线程打印信息");
,即
线程9 打印信息
主线程打印信息
否则:
主线程打印信息
线程9 打印信息
(2)Synchronized(同步锁)
张三在银行账户存有100元,经过多次的取200,存200后,账户还有多少钱?
package threadTest;
import java.sql.Time;
import java.util.concurrent.TimeUnit;
public class Account {
private String name;
private float amt;
public Account(String name,float amt) {
this.name=name;
this.amt=amt;
}
public void increaseAmt(float increaseAmt){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
amt+=increaseAmt;
System.out.println("增加:"+amt);
}
public void decreaseAmt(float decreaseAmt){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
amt-=decreaseAmt;
System.out.println("减少:"+amt);
}
public void printMsg(){
System.out.println(name+"账户现有金额为:"+amt);
}
public static void main(String[] args){
final int NUM=100;
Thread[] threads=new Thread[NUM];
final Account account=new Account("zhou",200);
for(int i=0;i<NUM;i++){
if(threads[i]==null){
threads[i]=new Thread(new Runnable() {
@Override
public void run() {
account.increaseAmt(100f);
account.decreaseAmt(100f);
}
});
threads[i].start();
}
}
for(int i=0;i<NUM;i++){
try {
threads[i].join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
account.printMsg();
}
}
分别多次运行,出现不同的结果。
增加:700.0
增加:700.0
增加:1300.0
增加:1300.0
增加:3900.0
....
减少:5500.0
减少:5800.0
zhou账户现有金额为:-100.0
不符合实际
加锁方法:
a.动态方法加锁
public synchronized void doSomething(){}
b代码块的修饰
- public void increaseAmt(float increaseAmt){
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- synchronized (this) {
- System.out.println(this);
- amt+=increaseAmt;
- }
- }
- public synchronized static void increaseAmt(float increaseAmt){
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- amt+=increaseAmt;
- }
- synchronized (AccountSynchronizedClass.class) {
- amt-=decreaseAmt;
- }
正确的形式:
package threadTest;
import java.util.concurrent.TimeUnit;
/**
* Synchronized 代码块
* @author 战国
*
*/
public class AccountSynchronizedBlock {
private String name;
private float amt;
public AccountSynchronizedBlock(String name,float amt) {
this.name=name;
this.amt=amt;
}
public void increaseAmt(float increaseAmt){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) {
System.out.println(this);
amt+=increaseAmt;
}
}
public void decreaseAmt(float decreaseAmt){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) {
System.out.println(this);
amt-=decreaseAmt;
}
}
public void printMsg(){
System.out.println(name+"账户现有金额为:"+amt);
}
public static void main(String[] args){
//多线程synchronized修饰代码块 ,每次计算的值都一样
final AccountSynchronizedBlock account=new AccountSynchronizedBlock("张三", 100.0f);
final int NUM=50;
Thread[] threads=new Thread[NUM];
for(int i=0;i<NUM;i++){
if(threads[i]==null){
threads[i]=new Thread(new Runnable() {
@Override
public void run() {
account.increaseAmt(100f);
account.decreaseAmt(100f);
}
});
threads[i].start();
}
}
for(int i=0;i<NUM;i++){
try {
threads[i].join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
account.printMsg();
}
}
(3)lock
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
Lock提供多种方式获取锁,有Lock、ReadWriteLock接口,以及实现这两个接口的ReentrantLock类、ReentrantReadWriteLock类。
package threadTest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockImp {
private Lock lock=new ReentrantLock();
private ReadWriteLock rwLock=new ReentrantReadWriteLock();
private List<Integer> list=new ArrayList<Integer>();
public void doReentrantLock(Thread thread){
lock.lock();
System.out.println(thread.getName()+"获取锁");
try {
for(int i=0;i<10;i++){
list.add(i);
}
} catch (Exception e) {
}finally{
lock.unlock();
System.out.println(thread.getName()+"释放锁");
}
}
public void doReentrantReadLock(Thread thread){
rwLock.readLock().lock();
System.out.println(thread.getName()+"获取读锁");
try {
for(int i=0;i<10;i++){
list.add(i);
}
System.out.println(list);
} catch (Exception e) {
}finally{
rwLock.readLock().unlock();
System.out.println(thread.getName()+"释放读锁");
}
}
public void doReentrantWriteLock(Thread thread){
rwLock.writeLock().lock();
System.out.println(thread.getName()+"获取写锁");
try {
for(int i=0;i<10;i++){
list.add(i);
}
} catch (Exception e) {
}finally{
rwLock.writeLock().unlock();
System.out.println(thread.getName()+"释放写锁");
}
}
/**
* @param args
*/
public static void main(String[] args) {
final LockImp lockImp=new LockImp();
final Thread thread1=new Thread();
final Thread thread2=new Thread();
final Thread thread3=new Thread();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread1 run");
lockImp.doReentrantLock(thread1);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread2 run");
lockImp.doReentrantLock(thread2);
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread3 run");
lockImp.doReentrantLock(thread3);
}
}).start();
lockImp.doReentrantReadLock(thread1);
lockImp.doReentrantReadLock(thread2);
lockImp.doReentrantReadLock(thread3);
lockImp.doReentrantWriteLock(thread1);
lockImp.doReentrantWriteLock(thread2);
lockImp.doReentrantWriteLock(thread3);
}
}
输出:
thread1 run
Thread-0获取锁
thread2 run
Thread-0释放锁
Thread-1获取锁
Thread-1释放锁
Thread-0获取读锁
thread3 run
Thread-2获取锁
Thread-2释放锁
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Thread-0释放读锁
Thread-1获取读锁
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Thread-1释放读锁
Thread-2获取读锁
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Thread-2释放读锁
Thread-0获取写锁
Thread-0释放写锁
Thread-1获取写锁
Thread-1释放写锁
Thread-2获取写锁
Thread-2释放写锁
如果为单个锁和线程,则输出:
Thread-0获取读锁
thread1 run
Thread-0获取锁
Thread-0释放锁
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Thread-0释放读锁