java多线程核心技术(一) 多线程技能

第一章 java多线程技能

1.1进程和多线程的概念

进程是操作系统的基础,当一个程序载数据集合运行时的集合,线程则是进程中独立运行的子任务。比如QQ.exe运行的时候 你可以同时聊天 还有视频。

1.1.1使用多线程的好处

同样的俩个任务,任务1和任务2如果在单任务的环境中,需要一个任务任务的去执行,而在多任务的情况中 我可以俩个任务同时执行,而且可以在俩个任务中进行随意切换。
在这里插入图片描述
这样使用多线程的好处显而易见,使CPU的利用率大大的得到提升。

1.2 多线程的使用
1.2.1实现多线程

在java的jdk开发包中,已经自带了多线程技术的支持。可以很方便地进行多线程编程。实现多线程编程有俩种,一种使继承 Thread类,一种是实现Runnable接口。
在学习之前我们先来看看Thread类的源码:

public class Thread implements Runnable 

从上面可以看到 Thread类其实是实现了Runnable的接口,它俩的唯一区别 就是 因为JAVA是单继承,所以不支持多继承,那么当一个类已经有父类的时候,就无法用继承Thread类的方法 实现多线程,那么实现接口就是实现多线程的方法
下面是俩种多线程的实现方式:

/**
 * 创建yourThred类继承 Thread类 然后重写run方法 ,在run方法中写多线程执行的语句
 */
class  YourThread extends Thread{
   private int count = 5;
   public YourThread(String name){
      super();
      this.setName(name);
   }
    @Override
    public void run() {
       super.run();
       while (count>0){
           count--;
           System.out.println(this.getName());
       }
    }
}
public class MyThread  {
    public static void main(String[] args) {
        YourThread yourThread1 = new YourThread("线程A");
        yourThread1.start();
        System.out.println("多线程学习");
    }
}
/**
 * 创建yourThred类实现 Runnable接口 然后实现run方法 ,在run方法中写多线程执行的语句
 * 然后再main方法中 通过Thread的构造方法 去创建一个Thread类
 */
class  YourThread implements Runnable{
   private int count = 5;
    @Override
    public void run() {
        System.out.println("多线程学习");
    }
}
public class MyThread  {
    public static void main(String[] args) {
        YourThread yourThread = new YourThread();
        Thread thread = new Thread(yourThread);
        thread.start();
    }
}
1.3 实例变量 和线程安全

以下俩段代码诠释了 线程共用一个实例变量,和不共用的区别

/**
 *在这段代码中 一共创建了二个线程类,所以每个类都有自己的实例变量,就不会存在俩个线程操控一个实例变量的情况
 */
class  YourThread extends Thread{
   private int count = 5;
   public YourThread(String name){
      super();
      this.setName(name);
   }
    @Override
    public void run() {
          while(count>0){
              count--;
              System.out.println(this.currentThread().getName()+""+count);
          }
    }
}
public class MyThread  {
    public static void main(String[] args) {
        YourThread yourThread1 = new YourThread("线程A");
        YourThread yourThread = new YourThread("线程B");
        yourThread.start();
        yourThread1.start();
    }
}

在这里插入图片描述

/**
 *在这段代码中  创建了一个线程子类,然后创建俩个线程类,运行这俩个线程类 会共用同一个实例变量 所以导致
 * 实例变量的值会出现重复的值,即俩个线程同时对实例进行了操控,产生了线程不安全
 */
class  YourThread extends Thread{
   private int count = 5;
   public YourThread(String name){
      super();
      this.setName(name);
   }
    @Override
    public void run() {
          while(count>0){
              count--;
              System.out.println(this.currentThread().getName()+"  "+count);
          }
    }
}
public class MyThread  {
    public static void main(String[] args) {
        YourThread yourThread1 = new YourThread("线程A");
       Thread thread = new Thread(yourThread1);
       Thread thread1 = new Thread(yourThread1);
       thread.start();
       thread1.start();
    }
}

在这里插入图片描述

1.4 currentThread方法

currentThread() 方法返回代码段正在被哪个线程调用的那个线程的信息,也是Thread类中的一个静态方法。

class thread extends Thread{
    public thread(){
        System.out.println(Thread.currentThread().getName());
    }
    @Override
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

public class MyThread  {
    public static void main(String[] args) {
        thread Thread1 = new thread();
        Thread1 .start();

    }
}

main
Thread-0

从上图可知第一次有main线程调用thread的构造方法所以获取的名字是main,然后创建的线程 启动 会获取到新线程的名称
这里还需要弄清楚俩个概念:

  • Thread.currentThread().getName():代表代码段正在被哪个线程调用的那个线程的信息
  • this.getName():表示创建的线程实例本身
1.5 isAlive() 方法

isAlive() 方法的功能是判断当前线程是否处于活动状态
活动状态就是线程已经启动(start)且尚未终止。线程处于正在运行(调用了run)或者准备开始运行的状态,就认为线程是存活的

class thread extends Thread{
    @Override
    public void run(){
        System.out.println(this.isAlive());
    }
}

public class MyThread  {
    public static void main(String[] args) {
        thread Thread1 = new thread();
        System.out.println("begin: "+Thread1.isAlive());
        Thread1 .start();
        System.out.println("end: "+Thread1.isAlive());

    }
}
begin: false
end: true
true

第一个由于处于新建状态,还没有调用 start 方法启动,因此不是处在活动状态
第二个因为在 run 方法中,说明已经启动了,且处于运行状态,因此也是处于活动状态
第三个因为线程还没有终止,此时线程还是处于活动状态
注意:如果线程是睡眠状态 那么isAlive()方法也会返回false;

1.6 sleep()方法

sleep() 的作用是在指定的毫秒数内让当前“正在执行的线程”休眠,即暂停执行,这个“正在执行的线程”指的是 this.currentThread() 返回的线程

1.7 getId() 方法

getId() 方法的作用是取得线程的唯一标识

public class MyThread  {
    public static void main(String[] args) {
        thread Thread1 = new thread();
        thread Thread2 = new thread();
        System.out.println(Thread1.getId());
        System.out.println(Thread2.getId());

    }
}

结果为:
12
13
1.8 停止线程

在 Java 中有以下 3 种方法可以终止正在运行的线程:

  1. 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程中止。
  2. 使用 stop() 方法强行终止线程,但是不推荐使用这个方法,该方法已被弃用。
  3. 使用 interrupt 方法中断线程。
1.8.1 使用标志位终止线程

在 run() 方法执行完毕后,该线程就终止了。但是在某些特殊的情况下,run() 方法会被一直执行;比如在服务端程序中可能会使用 while(true) { … } 这样的循环结构来不断的接收来自客户端的请求。此时就可以用修改标志位的方式来结束 run() 方法。可以通过在run方法中 抛出异常 这样最好终止线程了

1.8.2 使用 stop() 终止线程

虽然 stop() 方法确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且该方法已被弃用,最好不要使用它
为什么弃用stop:

  1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
  2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
1.8.3 使用 interrupt() 中断线程

现在我们知道了使用 stop() 方式停止线程是非常不安全的方式,那么我们应该使用什么方法来停止线程呢?答案就是使用 interrupt() 方法来中断线程。
需要明确的一点的是:interrupt() 方法并不像在 for 循环语句中使用 break 语句那样干脆,马上就停止循环。调用 interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。
也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定。这一点很重要,如果中断后,线程立即无条件退出,那么我们又会遇到 stop() 方法的老问题。
事实上,如果一个线程不能被 interrupt,那么 stop 方法也不会起作用。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值