多线程(二)

1.synchronized锁重入java

public class Service {
    synchronized public void service1(){
        System.out.println("service1");
        service2();
    }
    synchronized public void service2(){
        System.out.println("service2");
        service3();
    }    

    synchronized public void service3(){
        System.out.println("service2");
    }
}
//线程类
public class MyThread extends Thread{
    @Override
    public void run() {
        Service service=new Service();
        service.service1();
    }
}
//测试类
public class Run {
    public static void main(String[] args) {
        MyThread thread=new MyThread();
        thread.start();
    }
/*
output:
service1
service2
service3
*/
}

总结:本身能够再次获取本身的内部锁.也支持在父子类继承的环境中dom

2.出现异常,锁自动释放异步

public class Service {
    synchronized public void testMethod(){
        if(Thread.currentThread().getName().equals("a")){
            System.out.println("ThreadName="+Thread.currentThread().getName()
            +" run beginTime="+System.currentTimeMillis());
            int i=1;
            while(i==1){
                if((""+Math.random()).substring(0,8).equals("0.123456")){
                    System.out.println("ThreadName="+Thread.currentThread().getName()
                    +" run exceptionTime="+System.currentTimeMillis());
                    Integer.parseInt("a");
                }
            }
        }else{
            System.out.println("Thread B runt Time="+System.currentTimeMillis());
        }
    }
}
public class Test {
    public static void main(String[] args) {
        try {
            Service service=new Service();
            ThreadA a=new ThreadA(service);
            a.setName("a");
            a.start();
            Thread.sleep(500);
            ThreadB b=new ThreadB(service);
            b.setName("b");
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/*output:
ThreadName=a run beginTime=1523554493390
ThreadName=a run exceptionTime=1523554494218
//a报错,锁自动释放
Thread B runt Time=1523554494219
Exception in thread "a" java.lang.NumberFormatException: For input string: "a"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at us.codecraft.dxc.Service.testMethod(Service.java:16)
    at us.codecraft.dxc.ThreadA.run(ThreadA.java:36)
*/
}

3.同步不具备继承性ide

//父类
public class Main {
    synchronized public void serviceMethod(){
        try {
            System.out.println("int main 下一步 sleep begin threadName="
                    +Thread.currentThread().getName()+" time="+System.currentTimeMillis()
            );
            Thread.sleep(5000);
            System.out.println("int main 下一步 sleep end threadName="+
            Thread.currentThread().getName()+" time="+
                    System.currentTimeMillis()
            );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//子类
public class Sub extends Main{
    @Override
    public void serviceMethod() {
        try {
            System.out.println("int sub 下一步 sleep begin threadName="
                    +Thread.currentThread().getName()+" time="+System.currentTimeMillis()
            );
            Thread.sleep(5000);
            System.out.println("int sub 下一步 sleep end threadName="+
                    Thread.currentThread().getName()+" time="+
                    System.currentTimeMillis()
            );
            super.serviceMethod();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//线程A
public class ThreadA extends Thread{
    private Sub sub;
    public ThreadA(Sub sub){
        super();
        this.sub=sub;
    }

    @Override
    public void run() {
        sub.serviceMethod();
    }
}
//线程B
public class ThreadB extends Thread{
    private Sub sub;
    public ThreadB(Sub sub){
        super();
        this.sub=sub;
    }

    @Override
    public void run() {
        sub.serviceMethod();
    }
}
public class Test {
    public static void main(String[] args) {
        Sub subRef=new Sub();
        ThreadA a=new ThreadA(subRef);
        a.setName("A");
        a.start();
        ThreadB b=new ThreadB(subRef);
        b.setName("B");
        b.start();
    }
/*output:
int sub 下一步 sleep begin threadName=B time=1523556610729
int sub 下一步 sleep begin threadName=A time=1523556610729
int sub 下一步 sleep end threadName=A time=1523556615729
int sub 下一步 sleep end threadName=B time=1523556615729
int main 下一步 sleep begin threadName=A time=1523556615729
int main 下一步 sleep end threadName=A time=1523556620730
int main 下一步 sleep begin threadName=B time=1523556620730
int main 下一步 sleep end threadName=B time=1523556625730
*/
}

4.synchronized的弊端:测试

package us.codecraft.dxc;

/**
 * Created by Administrator on 2018/4/13.
 */
public class Task {
    private String getDate1;
    private String getDate2;
    public synchronized void doLongTimeTask(){
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            getDate1="长时间处理任务后从远程返回值1 threadName="+Thread.currentThread().getName();
            getDate2="长时间处理任务后从远程返回值2 threadName="+Thread.currentThread().getName();
            System.out.println(getDate1);
            System.out.println(getDate2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class CommonUtils {
    public static long beginTime1;
    public static long endTime1;
    public static long beginTime2;
    public static long endTime2;

}
public class MyThread1 extends Thread{
    private Task task;
    public MyThread1(Task task){
        super();
        this.task=task;
    }

    @Override
    public void run() {
        super.run();
        CommonUtils.beginTime1=System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime1=System.currentTimeMillis();
    }
}
public class MyThread2 extends Thread{
    private Task task;
    public MyThread2(Task task){
        super();
        this.task=task;
    }

    @Override
    public void run() {
        super.run();
        CommonUtils.beginTime2=System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2=System.currentTimeMillis();
    }
}
public class Run {
    public static void main(String[] args) {
        Task task=new Task();
        MyThread1 thread1=new MyThread1(task);
        thread1.start();
        MyThread2 thread2=new MyThread2(task);
        thread2.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long beginTime=CommonUtils.beginTime1;
        if(CommonUtils.beginTime2<CommonUtils.beginTime1){
            beginTime=CommonUtils.beginTime2;
        }
        long endTime=CommonUtils.endTime1;
        if (CommonUtils.endTime2>CommonUtils.endTime1) {
            endTime = CommonUtils.endTime2;
        }
        System.out.println("耗时"+((endTime-beginTime)/1000));

    }
/*output:
begin task
长时间处理任务后从远程返回值1 threadName=Thread-0
长时间处理任务后从远程返回值2 threadName=Thread-0
end task
begin task
长时间处理任务后从远程返回值1 threadName=Thread-1
长时间处理任务后从远程返回值2 threadName=Thread-1
end task
耗时6*/
}

一段时间内只能有一个线程被执行,另外一个线程必须等待当前线程执行完代码之后才能执行该代码块this

解决方法:使用同步代码块线程

public class Task {
    private String getDate1;
    private String getDate2;
    public void doLongTimeTask(){
        try {
            System.out.println("begin task");
            Thread.sleep(3000);
            synchronized (this){
            getDate1="长时间处理任务后从远程返回值1 threadName="+Thread.currentThread().getName();
            getDate2="长时间处理任务后从远程返回值2 threadName="+Thread.currentThread().getName();
            }
            System.out.println(getDate1);
            System.out.println(getDate2);
            System.out.println("end task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/**output:
begin task
begin task
长时间处理任务后从远程返回值1 threadName=t1
长时间处理任务后从远程返回值2 threadName=t1
end task
长时间处理任务后从远程返回值1 threadName=t2
长时间处理任务后从远程返回值2 threadName=t2
end task
耗时3
/
}

5.多个线程调用同一个对象中的不一样名称的synchronized同步方法或者synchronized(this)同步代码块时,调用的效果是按照顺序执行,也就是同步的,阻塞的code

synchronized同步方法和synchronized(this)同步代码块分别有两种做用:orm

对其余synchronized同步方法或者synchronized(this)同步代码块调用呈阻塞状态对象

同一时间只有一个线程能够执行或者synchronized()同步方法或者synchronized(this)同步代码中的代码

6.将任意对象做为对象监视器

public class Service {
    private String password;
    private String username;
    String anyString =new String();
    public void setUsernamePass(String username,String password){
        try {
            synchronized (anyString) {
                System.out.println("线程名为:" + Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "进入同步块");
                Thread.sleep(3000);
                this.username = username;
                this.password=password;
                System.out.println("线程名为:" + Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "离开同步块");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ThreadA extends Thread{
    private Service service;
    public ThreadA(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.setUsernamePass("a","aa");
    }
}
public class ThreadB extends Thread{
    private Service service;
    public ThreadB(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.setUsernamePass("b","bb");
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service=new Service();
        ThreadA threadA=new ThreadA(service);
        threadA.setName("A");
        threadA.start();
        ThreadB threadB=new ThreadB(service);
        threadB.setName("B");
        threadB.start();
    }
/*output:
线程名为:A在1522229473958进入同步块
线程名为:A在1522229476969离开同步块
线程名为:B在1522229476969进入同步块
线程名为:B在1522229479980离开同步块
//同步,阻塞,先由A进入,再由B进入
*/
}

总结:咱们能够看出synchronized(非this对象)若是是公共资源(调用同一个类对象,两个线程影响同一个anyString)就是实现同步,阻塞功能.由此咱们能够得出,若是synchronized(非this对象)锁住的是私有变量的话,就能够实现异步,非阻塞的功能,下面咱们来实验一下.

public class Service {
    private String password;
    private String username;
    public void setUsernamePass(String username,String password){
        try {
            String anyString =new String();//将变量设置为局部变量
            synchronized (anyString) {
                System.out.println("线程名为:" + Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "进入同步块");
                Thread.sleep(3000);
                this.username = username;
                this.password=password;
                System.out.println("线程名为:" + Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "离开同步块");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
/*output:
线程名为:A在1522229832397进入同步块
线程名为:B在1522229832397进入同步块
线程名为:A在1522229835408离开同步块
线程名为:B在1522229835408离开同步块
//两个线程同时进入方法,非阻塞,异步
*/
}

总结:大大提升了运行效率.

7.静态同步synchronized方法与synchronized(class)代码块

synchronized应用在static静态方法上,这样是对当前的*.class文件对应的class类进行持锁.

例子:

public class Service {
    synchronized public static void printA(){
        try {
            System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printA");
            Thread.sleep(3000);
            System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printA");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized public static void printB(){
        System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printB");
        System.out.println("线程名称为:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printB");
    }
}
public class ThreadA extends Thread{
    @Override
    public void run() {
        Service.printA();
    }
}
public class ThreadB extends Thread{
    @Override
    public void run() {
        Service.printB();
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadA a =new ThreadA();
        a.setName("a");
        a.start();
        ThreadB b=new ThreadB();
        b.setName("b");
        b.start();
    }
/*output:
线程名称为:a在1515601919412进入printA
线程名称为:a在1515601922412离开printA
线程名称为:b在1515601922412进入printB
线程名称为:b在1515601922412离开printB
*/
}

总结:synchronized关键字加到static静态方法上是给class类上锁,而synchronized关键字加到非static静态方法上是给对象加锁

相关文章
相关标签/搜索