美文网首页多线程
线程安全1 - synchronized、notify、wait

线程安全1 - synchronized、notify、wait

作者: 小超_8b2f | 来源:发表于2019-09-29 11:05 被阅读0次
  1. Runnable 和 Thread run() 都重写,执行Thread的run()
/**
 * 创建新线程时,即重写父类run方法,亦实现Runnable参数的run方法
 * 执行的是子类中重写的run方法,不是Runnable的run方法
 * @author guchunchao
 *
 */
public class TestThread {
    
    public static void main(String[] args) {
        System.out.println("main thread");
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable's method() instance");
                
            }
        }) {
            public void run() {
                System.out.println("Thread's method() override");
                
            };
        }.start();
    }
}
  1. 多线程共调非synchronized的打印方法,打印出纰漏

public class TestSynchronized {
    
    public static void main(String[] args) {
        TestSynchronized obj = new TestSynchronized();
        obj.init();
    }
    
    private void init() {
        OutPut out = new OutPut();
        new Thread() {
            @Override
            public void run() {
                while(true)
                    out.print("hello world");
            };
        }.start();
        
        new Thread() {
            @Override
            public void run() {
                while(true)
                    out.print("guchunchaoxixihaha");
            };
        }.start();
    }
    
    
    class OutPut {
        public void print(String str) {
            for(int i = 0; i < str.length(); i++) {
                System.out.print(str.charAt(i));
            }
            System.out.println();
        }
    }
}

错误结果:

guchunchaoxixihaha
guchunchaoxixiha
hello worha
guchunchaoxixihaha
guchunchaoxld
hello world

解决办法:在方法上➕synchronized关键字


面试题:
1.【子线程循环执行10次,主线程循环执行100次】50次

下面代码不加synchronized (MainSubThread.class) {}时输出语句交替执行,毫无章法可言,加上后则 synchronized包含的内部代码 for(10次 / 100次) 作为一个整体是连贯输出的,只有外面的主线程50次和子线程50次可能是交替的。

public class MainSubThread {
    public static void main(String[] args) {
        new Thread(new Runnable() { 
            @Override
            public void run() {
                //子线程循环调用50次某逻辑
                for(int i = 0; i < 50; i++) {
                    synchronized (MainSubThread.class) {
                        for (int j = 0; j < 10; j++) {
                            System.out.println("sub Thread run sequece of " + j + " loop of " + i);
                        }
                    }
                }
            }
        }).start();
        
        //主线程循环调用50次某逻辑
        for(int i = 0; i < 50; i++) {
            synchronized (MainSubThread.class) {
                for (int j = 0; j < 10; j++) {
                    System.out.println("main Thread run sequece of " + j + " loop of " + i);
                }
            }
        }
    }
}

  1. 面向对象方式封装重写版本
public class MainSubThread {
    public static void main(String[] args) {
        
        final Business business = new Business();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                //子线程循环调用50次某逻辑
                for(int i = 0; i < 50; i++) {
                    business.sub(i);
                }
            }
        }).start();
        
        
        //主线程循环调用50次某逻辑
        for(int i = 0; i < 50; i++) {
            business.main(i);
        }
    }
}

class Business {
    public synchronized void main(int i) {
        for (int j = 0; j < 10; j++)
            System.out.println("main Thread run sequece of " + j + " loop of " + i);
    }
    public synchronized void sub(int i) {
        for (int j = 0; j < 10; j++)
            System.out.println("sub Thread run sequece of " + j + " loop of " + i);
    }
}
  1. 交替执行版本(wait notify):
public class MainSubThread {
    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //子线程循环调用50次某逻辑
                for(int i = 0; i < 50; i++) {
                    business.sub(i);
                }
            }
        }).start();
        
        //主线程循环调用50次某逻辑
        for(int i = 0; i < 50; i++) {
            business.main(i);
        }
    }
}

class Business {
    private boolean bShouldSub = true;
    public synchronized void sub(int i) {
        if(!bShouldSub) {  //while 更健壮,根据API,可以防止伪唤醒
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (int j = 0; j < 10; j++)
            System.out.println("sub Thread run sequece of " + j + " loop of " + i);
        
        bShouldSub = false;
        this.notify();
    }
    
    public synchronized void main(int i) {
        if(bShouldSub) {//while 更健壮,根据API,可以防止伪唤醒
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (int j = 0; j < 10; j++)
            System.out.println("main Thread run sequece of " + j + " loop of " + i);
        
        bShouldSub = true;
        this.notify();
    }
}
wait()

 在等待Condition吋,允许发生 “虚假唤醒” 这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态说明。某个实现可以随意移除可能的 “虚假唤醒” ,但建议应用程序员总是假定这些 “虚假唤醒” 可能发生,因此总是在一个循环中等


伪唤醒,为什么判断用while不用if

  Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。2个线程要执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。锁是尚在代表要操作的资源的类的内部方法中,而不是线程代码中

  读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写🔐互斥,写🔐与写🔐互斥,这是由jvm自己控制的,你只要上好相应的🔐即可。如果你的代码只读取数据,可以很多人同时读,但不能同时写,那就上读🔐;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写🔐。总之,读的时候上读🔐,写的时候上写🔐。

一个面试题:一个缓存类!

相关文章

网友评论

    本文标题:线程安全1 - synchronized、notify、wait

    本文链接:https://www.haomeiwen.com/subject/jopzsctx.html