多线程笔记(一)关键字volatile、join、synchronized、Lock、Thread和Runnable

1. 关于volatile关键字

http://www.cnblogs.com/dolphin0520/p/3920373.html

2. 关于join的基础知识

join()方法的作用是等待线程对象销毁。
	join()方法具有能使线程排队运行的作用,有点类似于同步的效果。
join与synchronize的区别:
	join在内部使用wait()方法进行等待,底层用wait()来实现。
	synchronize关键字是以“对象监视器”为原理做同步操作。
join()除了无参方法之外,还重载了join(毫秒)的方法,此方法与sleep(毫秒)的区别是:
	join()操作底层用wait()来实现,可以释放锁。
	sleep()不会释放锁。
  1. 场景案例:使用2个线程,分别从1加到100,然后两个线程的结果求和。
    直接贴代码:
public class JoinMain {
    public volatile static int i = 0;
    public static class AddThread extends Thread {
        @Override
        public void run() {
            for (int j= 0; j < 101; j++){
                try {
                    Thread.sleep(10);
                    i+=j;
                    System.out.println("thread-1:"+i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class AddThread2 extends Thread {
        @Override
        public void run() {
            for (int k = 0; k < 101; k++){
                try {
                    Thread.sleep(10);
                    i+=k;
                    System.out.println("thread-2:"+i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String args[]) throws InterruptedException {
        AddThread at = new AddThread();
        AddThread2 at2 = new AddThread2();
        at.start();
        at.join();
        at2.start();
        at2.join();
        System.out.println("testResult:"+i);

    }
}

其中,public volatile static int i = 0;保证了有一个全局的不变的数据结构存在,方便计数。
join函数确保了两个线程不会交叉计算。
其中,

at.start();
at.join();
at2.start();
at2.join();

这个顺序不能变,否则结果会乱掉。

  1. 那么,如果想使用如下代码实现上述功能呢?
 thread1.start();
 thread2.start();
  thread1.join();
  thread2.join();

这时候,就要用到 synchronized 关键字了

由于刚刚的例子,我们使用了继承Thread方法的模式,本次,我们使用实现Runnable接口的方式。

/**
 * @className:
 * @Description:
 * @author: KevinHui
 * @createTime:2018/12/17 11:23
 */
public class SyncJoinMain implements Runnable {
    //开启一个线程
    static SyncJoinMain syncJoinMain = new SyncJoinMain();
    static volatile int i = 0;

    @Override
    public void run() {
        for(int t = 0; t<101;t++){
            synchronized (syncJoinMain){
                i+=t;
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(syncJoinMain);
        Thread t2 = new Thread(syncJoinMain);
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(i);
    }
}

执行结果为10100

这里要注意的是,synchronized锁住的必须是实现了Runnable接口或者继承了Thread的对象,而不能是其他类型。错误案例,请看如下代码:

public class BadLockOnInteger implements Runnable {

    public static Integer i = 0;
    static BadLockOnInteger instance = new BadLockOnInteger();


    @Override
    public void run() {
        for (int j = 0; j < 1000000; j++) {
            synchronized (i) {//这里同步的并不是同一个对象,因为i是以Integer关键字创建的
                //正确做法应该是 synchronized (instance)
                i++;
            }
        }
    }

    /**
     * 得到的结果并不是2000000,在多线程的操作中出现了错误
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String args[]) throws InterruptedException {
        Thread thread1 = new Thread(instance);
        Thread thread2 = new Thread(instance);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(i);
    }
}

synchronized和volatile的区别

1. synchronized关键字是防止多个线程同时执行一段代码,而volatile关键字在某些情况下性能要优于synchronized。
2. 但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。

synchronized和Lock的区别

https://www.jianshu.com/p/286d95eb7502

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值