多线程并发安全问题
当多个线程并发操作同一临界资源,由于线程切换实际不确定,导致操作临界资源的完整过程出现混乱从而导致各种不良后果
临界资源:操作该资源的完整过程同一时刻只能被单线程进行的资源
public class SyncDemo {
public static void main(String[] args) {
Table table = new Table();
Thread t1 = new Thread(){
@Override
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//主动要求线程放弃本次剩余时间片.模拟执行到这里时没时间发生切换
System.out.println(getName()+":"+bean);
}
}
};
Thread t2 = new Thread(){
@Override
public void run(){
while(true){
int bean = table.getBean();
Thread.yield();//主动要求线程放弃本次剩余时间片.模拟执行到这里时没时间发生切换
System.out.println(getName()+":"+bean);
}
}
};
t1.start();
t2.start();
}
}
class Table{
Thread.yield();//主动要求线程放弃本次剩余时间片.模拟执行到这里时没时间发生切换
synchronized上锁,表示这个进程正在被使用
private int beans = 20;
public synchronized int getBean(){
if(beans==0){
throw new RuntimeException("没有豆子了!");
}
Thread.yield();
return beans--;
}
}
同步块
有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高并发效率
synchronized(同步监视的对象){
需要同步执行的代码片段
}
public class SyncDemo2 {
public static void main(String[] args) {
Shop shop = new Shop();
Thread t1 = new Thread("范传奇"){
@Override
public void run(){
shop.buy();
}
};
Thread t2 = new Thread("王克晶"){
@Override
public void
run(){
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
/**
* 成员方法上使用synchronized,同步监视器对象不可选,就是this
*/
public void buy() {
try {
Thread t = Thread.currentThread();
System.out.println(t.getName()+":正在挑选衣服");
Thread.sleep(5000);
/*
同步块使用时必须在synchronized()中指定同步监视器对象,该对象必须满足两点
1:必须是引用类型的实例
2:多个线程看到的必须是同一个对象
*/
//synchronized (new object()) { new一定产生新对象,因此一定不能作为同步监视器使用
// synchronized (t) { 这里的t是当前执行代码的线程,不同线程t标识的不同
synchronized (this) {
System.out.println(t.getName()+":正在试衣服");
Thread.sleep(5000);
}
System.out.println(t.getName()+":结账离开");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
静态方法上使用synchronized后,所有对象不可选,指定的是当前类的类对象
即:class实例
JVM中每一个被加载的类都有且只有一个Class实例与之对应
Thread t1 = new Thread(){
@Override
public void run(){
Foo.doSomething();
}
};
Thread t2 = new Thread(){
@Override
public void run(){
Foo.doSomething();
}
};
class Foo{
public static void doSomething(){
synchronized (Foo.class) {
Thread t = Thread.currentThread();
System.out.println(t.getName()+"正在执行doSome方法");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"执行完doSome方法");
}
}
}
互斥性
当使用多个synchronized锁定多个代码片段并且指定的同步监视器对象是同一个时,这些代码片段之间就是互斥的
public class SyncDemo4 {
public static void main(String[] args) {
Boo boo = new Boo();
Thread t1 = new Thread(){
@Override
public void run(){
boo.methodA();
}
};
Thread t2 = new Thread(){
@Override
public void run(){
boo.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public void methodA(){
Thread t = Thread.currentThread();
System.out.println(t.getName()+"执行a方法");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"执行完a方法");
}
public void methodB(){
Thread t = Thread.currentThread();
System.out.println(t.getName()+"执行b方法");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+"执行完b方法");
}
}