synchronized通常作为本地锁,分布式项目下要用分布式锁。
线程的安全问题与线程的同步机制
类似于数据库的脏读幻读的情况
synchronized(同步监视器){
//需要同步的代码
}
说明:
需要同步的代码,即为操作共享数据代码
共享数据即为多个线程需要操作的数据,例如tiket票数
需要被操作的代码被synchronized包裹后,一个线程操作时其他线程必须等待
同步监视器俗称锁,哪个线程获得了锁即获得了操作数据的权力
同步监视器,可以用任意一个对象充当,但是注意所有线程共用一个锁。
比喻:上厕所锁门要加锁,如果没有锁,后面一个人同时进来,两个人上同一个厕所不安全。
public class sale {
public static void main(String[] args) {
salePic saller1=new salePic();
Thread t1=new Thread(saller1);
Thread t2=new Thread(saller1);
Thread t3=new Thread(saller1);
t1.start();
t2.start();
t3.start();
}
}
class salePic implements Runnable{
int total=1000;
@Override
public void run() {
while(total>0){
//this表示调用该方法的对象,这里指saller1确定是唯一的
synchronized (this){
if (total>0){
System.out.println(Thread.currentThread().getName()+"售出第"+total+"张票");
total-=1;
}
}
}
}
}
public class sale2 {
public static void main(String[] args) {
salePic2 s1=new salePic2();
salePic2 s2=new salePic2();
salePic2 s3=new salePic2();
s1.start();
s2.start();
s3.start();
}
}
class salePic2 extends Thread {
int total=1000;
@Override
public void run() {
while(total>0){
//在继承Thread类方式中同步监视器慎用,这里使用Window.class
synchronized (Window.class){
if (total>0){
System.out.println(Thread.currentThread().getName()+"售出第"+total+"张票");
total-=1;
}
}
}
}
}
public class sale {
public static void main(String[] args) {
salePic saller1=new salePic();
Thread t1=new Thread(saller1);
Thread t2=new Thread(saller1);
Thread t3=new Thread(saller1);
t1.start();
t2.start();
t3.start();
}
}
class salePic implements Runnable{
int total=100;
@Override
public void run() {
while(total>0){
show();
}
}
//方法非静态时,默认监视器为this,此时为this
public synchronized void show(){
if (total>0){
System.out.println(Thread.currentThread().getName()+"售出第"+total+"张票");
total-=1;
}
}
}
可以将需要执行的多线程任务用synchronized标识为特定方法
public class sale2 {
public static void main(String[] args) {
salePic2 s1=new salePic2();
salePic2 s2=new salePic2();
salePic2 s3=new salePic2();
s1.start();
s2.start();
s3.start();
}
}
class salePic2 extends Thread {
static int total=10;
@Override
public void run() {
while(total>0){
show();
}
}
//非静态时监视器为this,在这种情况不可以,因为s1 s2 s3为不同对象
//静态时监视器为当前类,window.class
public static synchronized void show(){
if (total>0){
System.out.println(Thread.currentThread().getName()+"售出第"+total+"张票");
total-=1;
}
}
}
注意在Thread继承使用时,调用run()的为不同对象,只加上synchronized是没有用的。可以使用static,但是也要尽量避免使用这种方法。
如果共享数据完整声明在一个方法中适合使用synchronized方法
非静态方法,默认监视器为this
静态方法,默认监视器为当前类本身
好处 | 弊端 |
---|---|
解决了线程安全问题 | 操作共享数据时,实际时串行线程,性能要低一些 |
推荐阅读: