java multithreaded core api and related concepts (a)

This blog summarizes the learning thread core api and related concepts, bold can be understood as the focus, the other is my understanding of it

Personally think that these are the basis for learning java multi-threaded, do not understand familiar with these, the latter can not learn drops

table of Contents

1. What are the advantages and thread

Second, how to use multithreading

Third, the security thread,

Four, synchronized execution narrative

Fifth, several API:

Sixth, stop the thread, the thread suspended  

Priority VII threads

Eight, daemon thread

A first thread and find out what is his advantage , I think the sentence can be said clearly, many subtasks thread is a process. That may browse the Web and download after you open the browser on such things, though you you like to do two things at the same time, but in fact is \ cpu kept switching between two tasks, just switch speed quickly , feeling is running simultaneously, another thread is asynchronous drops.

Once you understand this concept, look at the advantages of thread, said multi-threaded execution speed can make the task faster, I think this sentence is not entirely accurate, and also just a little of it.

First multi-threaded execution speed is submitted built on a basis of the time more than one task execution time is unequal , what does that mean? For example, you now have two tasks, when the task is one with 10 seconds Task II when 1 second, if you order to perform these two tasks, the task a required 10 seconds, two tasks performed one second, but the two tasks waiting time also there are 10 seconds, it is seen as the implementation of 11 seconds, which total execution time is 21 seconds, but if you use multiple threads do? May be like this, perform a task one second, and then switch to the task Second, the implementation of Task 2 second, then switch back after a mission, this way, then, it is clear that two task waiting time is reduced, it is even more execution time short, corresponding also is our execution speed becomes faster. Of course just my own understanding, if the execution time is equal to you if, in fact, did not switch to switch to submit efficiency, but this time still have to use multiple threads for spreading child?

Because another advantage of multi-threading is the ability to run multiple tasks , the total can not let the browser can only open a window it, very simple, these two advantages.

Second, how to use multithreading

1. Use multi-threading, the two approaches, quite simply, the first inheritance Thread class, the second to achieve Runnable interface, which is actually two kinds of java does not support multiple inheritance, using the former method, you can not inherit from other classes of but to achieve Runnable, then it is possible, and you can also implement other interfaces, more flexible, essentially no difference, you will find open source Thread he also implements the Runnable interface, in addition to pay attention to realization Runnable interface, it is generally used when an instance of the class, use it to initialize a Thread class, class start the start. as follows:

 

       MyRunnable m = new MyRunnable (); // implements Runnable interface 
        the Thread M1 = new new the Thread (m); 
        m1.setName ( "my thread"); 
        m1.start ();

 

 

 

After 2. After inheriting, you need to do is to write run () method as well as his other methods may be required to use Thread.start start threads (), note that using this method, cpu will be added to perform this task columns were to go, after allocation of the resource scheduling tasks according to certain rules, schedule the task execution means that the run () method of this thread among.

3. Here we must understand a point, scheduling order between the same priority thread is random, unrelated and code sequence, this would not have said, very simple drops, do not believe they write a test program on the line.

Third, the security thread,

What we have mentioned thread unsafe, this insecurity is the meaning of this: First, there is a premise, no matter how many threads, these threads are operating on the same subject or by the same thread initialization, this situation of insecurity following:

 

ackage 第一章;

import javax.swing.plaf.TableHeaderUI;

class MyRunnable implements Runnable{
int count = 10;
public void run(){
count--;
System.out.println(Thread.currentThread().getName() + " " + count);
}
}
public class test1{
public static void main(String[] args){
MyRunnable m = new MyRunnable();
Thread m1 = new Thread(m, "A");
Thread m2 = new Thread(m,"B");
Thread m3 = new Thread(m,"c");
Thread m4 = new Thread(m,"D");
Thread m5 = new Thread(m,"E");
m1.start();
m2.start();
m3.start();
m4.start();
m5.start();
}
}

 

输出的结果每一次都是不一样的,我们期望的是count从10减到5并输出每一个数值,但是事实上的话,可能B线程已经获取到了count的值,这时候准备执行减一操作并输出,但是程序跳到A线程,执行了count--操作,B可能本来获取的值是10,之后准备count--,然后输出9,但是在这两部操作之间,count被A线程又给减一了,那么B线程获取到count的值时,就获取到了A线程更改之后的值,8,但是他原本获取到的值是9,。也就是说原本输出9,现在输出了8,这很明显是不安全的。。。。这样说不知道清楚不。输出结果如下:

"C:\Program Files\Java\jdk-11.0.1\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar=60024:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.3\bin" -Dfile.encoding=UTF-8 -classpath C:\learn\java\practice\out\production\threadTest 第一章.test1
A  8
B  8
D  6
c  5
E  7

Process finished with exit code 0

下面这种情况是安全的:

就是将count变量写在run() 函数内部,让他成为局部变量,这样每一个线程虽然是由同一个对象初始化的,但是他们的count是属于各自的,你无法在A线程里更改B线程的count的值,这时候就是安全的,就这样,不难理解,这里就不放代码啦。

这里为了解决我们的不安全问题,引出了synchronized概念,

四,synchronized执行过程叙述

这个关键字其实就是给一个对象的之中的某个方法上锁,每当一个线程访问该对象的该方法时,他会首先拿到这个锁,然后开始执行里面的代码,之后如果有另一个线程再来执行同一个对象的该方法,他会先尝试拿到锁,拿不到的话就会一直等着,直到锁被释放,再拿到锁执行代码,这样子就解决了安全问题,因为相当于每一个线程进入该方法之后,就是它自己的领地了,对count变量的操作都是以它自己为标准的,其他线程不能在中途更改count的值,直到该线程执行完毕。

五,几个API:

1.CurrentThread()   :获取当前线程,当前线程指的是当前代码片段是在哪一个线程上被调用的,比如下面的代码,构造函数MyRunnable()  是在main  线程当中被调用的,但是run()函数却是在线程A中调用的,  另外注意和this,getName()  的区别,后者是针对于当前this对象而言的Name

class MyRunnable implements Runnable{
    int count = 10;
    MyRunnable(){
        System.out.println(Thread.currentThread().getName());    //输出   main
    }
    synchronized public void run(){
            count--;
            System.out.println(Thread.currentThread().getName() + "  " + count);   //输出  A 
    }
}
public class test1{
    public static void main(String[] args){
        MyRunnable m = new MyRunnable();
        Thread m1 = new Thread(m, "A");
        m1.start();
    }
}

2.isAlive():当前线程是否处于活动状态,简单地说就是是否start()了并且run()  函数还没有运行完  ,用法:Thread.CurrentThread.isAlive()

3.sleep():  让当前线程休眠一段时间,单位毫秒,注意这里这个当前线程指的是正在运行的线程,就是当前代码片段处于哪一个线程当中,注意放在try语句中,用法:Thread.sleep()

4.getId():  获取当前线程唯一标识

六,停止线程,暂停线程  

概述:停止线程简单来说就是让cpu放弃当前线程的操作,先去执行其他线程,但是如果使用不当,会有数据不同步,独占锁等问题

终止线程的方法:

1.线程run函数调用结束,自动结束

2.调用  interrupt 函数

 Thread.interrupt() : 这个函数并不是说立刻停止停止线程,让线程停止操作,而是说在当前位置给线程加一个标识,表示该线程是应该停止的,但是并不会立即停止,那如果想要真正的停止该怎么办呢?使用  isTerrupted()和interrupted(),简单来讲,就是使用interrupt()停止线程添加标识之后,再使用相应的函数判断是否存在这个停止标识,存在的话就不执行某一些代码了,这样来达到停止的效果,但是这两个函数是不同的,看下面

interrupted(): 测试当前线程是否中断,如果中断了,就将中断标识,或者说状态清除掉。简单来讲就是执行完这个函数,线程一定是处于运行状态的

isInterrupted():  测试线程是否中断,没有清楚中断状态的功能,并且注意判断的并不是当前线程

理解两点:1,当前线程和线程的区别,2.是否会清除中断状态,

看下面例子:

Thread.interrupt() :

 

class MyRunnable implements Runnable{
    int count = 10;
    MyRunnable(){
        System.out.println(Thread.currentThread().getName());
    }
    public void run(){
        for(int i=0;i<1000;i++)
        {
            System.out.println(i);
        }
    }
}
public class test1{
    public static void main(String[] args){
        MyRunnable m = new MyRunnable();
        Thread m1 = new Thread(m, "A");
        m1.start();
        m1.interrupt();                      //注释该行,不注释下一行,输出true,false
        //Thread.currentThread().interrupt();
        System.out.println("测试是否中断1:"+Thread.interrupted());    //输出false
        System.out.println("测试是否中断2:"+Thread.interrupted());   //输出false 
     }
}

 

根据运行结果false来讲,我们停止了m1,线程,但是输出为false,因为调用interrupted方法代码处于的线程是main线程,main并没有停止,所以输出false,但是如果将注释去掉,将m1.interrupt()注释掉,会输出true ,false,为什么第二是false?这就是因为该函数具有清除中断状态的作用,第一次执行之后main就不再是中断状态了,所以输出false

isterrupted()方法:不具有清除状态作用,检测的是线程对象,一个具体的对象,不是当前线程,如下

package 第一章;

import javax.swing.plaf.TableHeaderUI;

class MyRunnable implements Runnable{
    int count = 10;
    MyRunnable(){
        System.out.println(Thread.currentThread().getName());
    }
    public void run(){
        for(int i=0;i<1000;i++)
        {
            System.out.println(i);
        }
    }
}
public class test1{
    public static void main(String[] args){
        MyRunnable m = new MyRunnable();
        Thread m1 = new Thread(m, "A");
        m1.start();
        m1.interrupt();
        //Thread.currentThread().interrupt();
        System.out.println("测试是否中断1:&&&&&&&&&&&&&&&&&&&&&&&"+m1.isInterrupted());  //输出true
        System.out.println("测试是否中断2:&&&&&&&&&&&&&&&&&&&"+m1.isInterrupted());       //输出true
    }
}

都输出true,就是因为他们调用的是对象m1的,m1被停止了,所以肯定输出true,不过注意,这个true会输出在任意位置,cpu调用决定的,所以你如果测试的话加点标识找起来方便。

所以,结合来讲的话,停止线程,run方法可以修改为如下:

public void run(){
        for(int i=0;i<1000;i++)
        {
            if(Thread.interrupted()){
                System.out.println("停止啦");
                break;
            }
            System.out.println(i);
        }
    //如果给这里加上语句,不判断是否停止,他还是会运行的 }

执行结果,可以看到输出了一些数字之后就停止了

。。。
205 206 207 208 209 210 211 212 停止啦 Process finished with exit code 0

当然这是一种软性的停止,你需要判断他是否停止了,下面介绍一种硬性的停止,抛出异常,很简单,将run 方法改为如下:

    public void run(){
        try{
        for(int i=0;i<1000;i++)
        {
            if(Thread.interrupted()){
                System.out.println("停止啦");
                throw new InterruptedException();
            }
            System.out.println(i);     
    }
    //for循环外面有语句也不会执行了,捕捉到异常
    }catch (InterruptedException e){ e.printStackTrace(); } }

一种情况,在沉睡中停止线程,

什么意思呢?假设你现在线程中断了,然后你再去调用Thread.sleep()函数让线程休眠,或者线程已经休眠了,你再去调用interrrupt()函数,那就会产生异常,并清除线程的中断状态。这两种情况是对立矛盾的,所以会产生异常,并且因为产生了异常,所以线程一定是被中断的

比如下面的代码,m1.start()之后,m1线程进行了sleep(),之后在main中又中断了m1线程,这明显是不合理的,所以会输出异常之中的内容

class MyRunnable implements Runnable{
    int count = 10;
    MyRunnable(){
        System.out.println(Thread.currentThread().getName());
    }
    public void run(){
        try{
        for(int i=0;i<1000;i++)
        {
            System.out.println(i);
            Thread.sleep(1000);
        }}catch (InterruptedException e){
            System.out.println("先休眠再停止");
            e.printStackTrace();
        }
    }
}
public class test1{
    public static void main(String[] args){
        MyRunnable m = new MyRunnable();
        Thread m1 = new Thread(m, "A");
        m1.start();
        try {                 //加这个语句是为了让m1的中断执行在睡眠之后
            Thread.sleep(10);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        m1.interrupt();         
    }
}

输出如下:

main
0
先停止再休眠
java.lang.InterruptedException: sleep interrupted
    at java.base/java.lang.Thread.sleep(Native Method)
    at 第一章.MyRunnable.run(test1.java:15)
    at java.base/java.lang.Thread.run(Thread.java:834)

Process finished with exit code 0

 

3.使用stop

这种方法已经被废除了,会造成很多问题

最简单的一个问题,数据不同步,假设你去银行,取1000,存1000,然后给你操作时候,这两个操作时在一个方法里面的,并且这个方法是上了锁的。在程序执行完了取1000之后,程序去上了个厕所,休眠了1秒,休眠期间,你使用了stop函数将线程强行停止,释放了对象锁,相当于后面存1000这个操作就没有做了,这很明显是不合理的,数据不同步了。

4.暂停线程

暂停线程是说将当前线程的操作暂停,过一会再回来继续执行,注意和中断的区别,它并不会释放对象锁

suspend()暂停函数,      

resume()恢复函数

这两个函数也已经被废除了,因为可能造成独占锁和不同步的问题,废除我们也要知道他为撒子废除了,不想看的朋友可以跳过下面

独占锁问题:

不想放太多的代码,放一点,然后用文字说明,更能表达思路

有这样一个对象,比较简洁,不想写没用的代码,意思就是碰到名字为a的线程,就暂停当前线程

 
 
class test{
  synchronized public void printStr() { if(Thread.currentThread().getName().equals("a")){
       System.out.println("打印。。。。。"); Thread.currentThread().suspend(); } }
}
class MyRunnable implements Runnable{
    int count = 10;
    MyRunnable(){
        System.out.println(Thread.currentThread().getName());
    }
    public void run() {
       //调用test实例的printStr方法
    }
}

现在,你初始化了a,b两个线程,使用了一个MyRunnable实例初始化的,然后你先start了a线程,a线程执行了printStr()方法,获取到了test实例的对象锁,然后被suspend了,但是它并没有释放test实例的对象锁,这时候如果b线程开启,他是无法执行printStr()方法的,因为它他拿不到对象锁,只能等着,这是不合理的。而且这里有一个有意思的问题,如果你这里使用了suspend的话,你如果想要在其他线程里面使用System.out.println()  方法,是不可以的,因为out对象的println()方法已经被锁定了。就是说你无法拿到他的锁,使用不了这个方法了,看下面的例子

class MyThread extends Thread{
    private  int i=0;
    public void run(){
        while(true){
            System.out.println(i);    //占用了println() 方法
            i++;
        }
    }
}
public class test1{
    public static void main(String[] args){
         MyThread m = new MyThread();
         m.start();
        try {
            Thread.sleep(10);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        m.suspend();
        System.out.println("main");       //不会打印
    }
}

输出结果就是打印到某一个数字然后停止,永远不会打印  main  ,其实你看一下println()方法源码就明白了:里面的代码被锁住了,a线程独占了这个锁

   public void println(int x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

不同步问题:

这个我觉得和前面stop的问题是一样的,不说了

七,线程的优先级

概述:前面我们看到的main线程还有自己创建的线程,代码执行都是随机的,55开滴,但是现实中线程肯定是有轻重缓急的,所以就有了线程优先级这一个概念,线程优先级高的执行的概率会大一点,但是也不是一定的,只是相对来讲大一点。

个人感觉这块没撒说的,就几个概念也都很好理解,自己写一些代码看看就行。

1.setPriotity(int )  设置优先级

2.getPriotity()   获取优先级

3.优先级具有继承性:比如你在A线程里启动了B线程,则B线程的优先级是和A线程一样的,除非你手动进行了设置。很简单吧

4.优先级具有随机性:这个也很理解,优先级高的不一定每一次都比优先级低先执行完,因为cpu在调度的时候肯定是以概率的方式来调度线程的,概率嘛,什么都有可能,只能说样本足够大时,优先级高的一定先执行完。

八,守护线程

java里面有两种线程,用户线程和守护线程,用户线程就是我之前定义的那些,当然也包括main线程,守护线程,举一个最简单的例子,java的垃圾回收机制,它是在什么时候回收的呢?你会跟随着用于线程,有没有delete的空间了,就清除掉它,直到所有线程都结束之后,它才会自动销毁。简单来说,就是一直陪伴着用户线程,帮助用户线程做一些事情,用户线程全部结束了,它也就结束了。

设置方法:thread.setDaemon(true);   默认是false的

个人觉得可能做一些需要不停的做的事情会用到该线程。

 

Guess you like

Origin www.cnblogs.com/eenio/p/11276264.html