Java 多线程核心编程一 --- Java 多线程编程基础和 synchronized 关键字

1、线程的实现的方式

实现多线程的方式有两种:
1. 继承 Thread
2. 实现 Runnable

1.1 继承 Thread

 public class MutiThread extend Thread{
     @override
     public void run(){
        .....
     }
 }

1.2 实现 Runnable

public class MutiThread implements Runnable{
     @override
     public void run(){
        .....
     }
}

具体的调用线程:

mThread.start();
  1. 从构造函数Thread(Runnable runnable) 可知不光可以传入实现了Runnable
    接口的对象,还可以传入 Thread对象,这样就可以 Thread对象的 run()方法交由其他的线程进行调用。
  2. Thread.java 类中的 start() 方法是通知“线程规划器”此时线程已经准备就绪,等待调用线程对象的 run() 方法。这个过程其实是让系统安排一个时间来调用 Thread中的 run()方法,也就是让线程得到运行,启动线程,具有异步执行的效果。如果调用 mThread.run() 方法就不是异步执行,而是同步执行,那么此时线程对象不是交给“线程执行器”来进行处理,而是由 mThread.run() 所在的线程调用 run() 方法。
  3. 线程是一个子任务,也就是说在使用子线程技术的时候,代码的运行的结果与代码执行顺序或调用顺序无关,而在同步线程中代码的执行顺序和代码的顺序是一致的。

2、线程安全问题

非线程安全主要是指多个线程同一个对象同一个实例变量进行操作时会出现的值被更改、值不同步的情况,进而影响程序的执行流程。

2.1 线程不共享数据

线程不共享数据即为每个线程的私有的变量,此时当然就不会发生线程安全问题。
一个简单的例子来说明这种情况:

public class CustomThread extends Thread{
    int count = 0;
    @Override
    public void run(){

    ....
    }
}

具体调用:

public class Run{
    public static void main(){
        CustomThread mCustomThreadA = new CustomThread();
        CustomThread mCustomThreadB = new CustomThread();
        CustomThread mCustomThreadC = new CustomThread();
        mCustomThreadA.start();
        mCustomThreadB.start();
        mCustomThreadC.start();
    }
}

很明显,此时变量 count 便属于线程不共享数据,因为每个对象都有自己内存区域,这没什么可说的,不在这浪费口舌了。

2.2 线程共享数据

同样我们通过一个例子来说明什么是线程不共享数据;

public class CustomThread extends Thread{
    int count = 5;
    @Override
    public void run(){
        count--;
        sysout("thread name is " + this.currentThread().getName() + "count = "+ count);
    }
}
public class Run{
    public static void main(){
        CustomThread mCustomThread = new CustomThread();
        Thead threadA = new Thead(mCustomThread,"A");
        Thead threadB = new Thead(mCustomThread,"B");
        Thead threadC = new Thead(mCustomThread,"C");
        Thead threadD = new Thead(mCustomThread,"D");
        Thead threadE = new Thead(mCustomThread,"E");
        threadA.start();
        threadB.start();
        threadC.start();
        threadD.start();
        threadE.start();
    }
}

打印结果:

thread name is A,count = 3
thread name is C,count = 3
thread name is B,count = 2
thread name is D,count = 2
thread name is E,count = 0

此时,变量 count便属于线程共享数据,因为threadA threadB访问的为同一个对象mCustomThread的同一个变量(线程安全出现的条件:1.多个线程 ;2.同一个对象; 3.同一个实例变量)。显然上面的结果不是我们想要的结果,我们想要的结果是 count依次递减。

2.3 线程安全问题的原因

就拿上面的例子中 count-- 来说,在有些 JVm 中,count-- 的操作分为三步:
1. 取得 count的值
2. 计算count - 1
3. 对 count进行赋值
在以上的三步中,如果有多个线程同时访问并进行相关变量的操作,那么一定会出现线程安全问题。

3、 线程安全问题的解决办法 – synchronized 关键字

通过在 run 方法前加入 synchronized关键字,使多个线程在执行run方法的时候以 排队 的方式执行。当一个线程执行 run方法前,先判断 run 方法上有没有被上锁,如果上锁,说明现在有其他线程正在调用run 方法,必须等其他线程执行完 run方法才可以执行run方法。

具体代码:

public class CustomThread extends Thread{
    int count = 5;
    /**
     * 添加 synchronized 关键字
     */
    @Override
    synchronized public void run(){
        count--;
        sysout("thread name is " + this.currentThread().getName() + "count = "+ count);
    }
}
public class Run{
    public static void main(){
        CustomThread mCustomThread = new CustomThread();
        Thead threadA = new Thead(mCustomThread,"A");
        Thead threadB = new Thead(mCustomThread,"B");
        Thead threadC = new Thead(mCustomThread,"C");
        Thead threadD = new Thead(mCustomThread,"D");
        Thead threadE = new Thead(mCustomThread,"E");
        threadA.start();
        threadB.start();
        threadC.start();
        threadD.start();
        threadE.start();
    }
}

打印结果:

thread name is A,count = 4
thread name is C,count = 3
thread name is B,count = 2
thread name is D,count = 1
thread name is E,count = 0

当一个线程想要执行同步方法里面的代码时,该线程首先尝试去拿这把锁,如果能拿到这把锁,那么这个线程就可以执行 ·synchronized` 里面的代码,如果拿不到这把锁,那么这个线程就会和其他没有拿到锁的线程不断的尝试去拿这把锁,直到拿到为止。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值