线程知识点,小归纳(笔记)

 

首先对一些简单概念进行理解

进程:程序运行资源分配的最小单位,进程内部有多个线程,并共享整个进程的资源。

线程:CPU调度的最小单位

并发和并行的区别:

并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。(在食堂有八个窗口,八个窗口并发)

并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。(每个窗口30s能给一个儿打饭,并发度为16)

 

线程创造三种方式:

  1.继承Thread的父类

  2.实现Runnable的接口

  3.实现Callable的接口

  (java类是单继承和多实现)。

 

package thread.cn;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class createThread {
    private static SimpleDateFormat formater =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss_SSS");
    public static class CreateThread1 extends Thread{
        public void run(){
            
                try {
                    while (!isInterrupted()) {
                        System.out.println(Thread.currentThread().getName() + "is running");
                    } 
                } finally {
                    System.out.println("finally");
                } 
            
        }
    }
    public static class CreateThread2 implements Runnable{
        
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            while(!Thread.currentThread().isInterrupted()) {
            try {
                    System.out.println(Thread.currentThread().getName() + "is running");
                    System.out.println("UseThread:"+formater.format(new Date()));
                    Thread.currentThread();
                    Thread.sleep(200);
                }
             catch (InterruptedException e) {
                System.out.println(threadName+" catch interrput flag is "
                        +Thread.currentThread().isInterrupted()+ " at "
                        +(formater.format(new Date())));
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
            System.out.println(threadName);    
            
        }
            System.out.println(threadName+" interrput flag is "
                    +Thread.currentThread().isInterrupted());
        }
    }
    
    public static class CreateThread3 implements Callable<String>{

        @Override
        public String call() throws Exception {
            System.out.println("this is Callable!");
            return "Callable";
        }
        
    }
    public static void main(String[] args) throws Exception {
        
          //1.继承Thread父类 
        Thread method1 = new CreateThread1(); 
        method1.start();
         method1.interrupt();
         
        
        //2.实现Runnable接口 
        CreateThread2 method2 = new CreateThread2(); 
        Thread t = new Thread(method2);
        t.start(); 
        System.out.println("Main:"+formater.format(new Date()));
        Thread.sleep(800);
        t.interrupt();
      
        
          //3.实现Callable接口 
        CreateThread3 method3 = new CreateThread3();
          FutureTask<String> futureTask = new FutureTask<>(method3);
          new Thread(futureTask).start();
         
         
    }
}

 

 

  中断线程

  stop过于强硬,对线程安全不友好,所以一般不用。

  interrupt()中断一个线程,并不是强行关闭这个线程,而是打个招呼(java线程是协作式),给中断标志位设置为true;

  isInterrupted()判断当前线程是否处于中断状态。

  static方法interrupted()判断当前,断标志位设置为false。

  需要注意到的是在catch到InterruptedException e 后,中断标志位会被取消,需要重新设置中断标志位才会使线层中断

catch (InterruptedException e) {
                System.out.println(threadName+" catch interrput flag is "
                        +Thread.currentThread().isInterrupted()+ " at "
                        +(formater.format(new Date())));
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }

 

线程的状态图

 

 

 

join() 

  当A线程调用调用此方法,使得当前在运行的B线程与该线程合并,即:等待A线程结束,B线程才能继续运行,在这时间段内,B处于等待状态。

 

package thread.cn;

public class joinAndyield {
    public static class Testjoin implements Runnable{
    
        @Override
        public void run() {
            String threadName ="ThreadName:"+ Thread.currentThread().getName();
            for(int i = 0 ; i <5 ;i++) {
                System.out.println(threadName);
                Thread.currentThread();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws Exception {
        Testjoin testjoin = new Testjoin();
        Thread t = new Thread(testjoin);
        t.setName("testJoin");
        t.start();
        Thread.sleep(1000);
        t.join();
        for (int i = 0; i <= 5; i++) {
            System.out.println("I am main Thread");
      }
    }
}    

 

在未写t.join之前,测试线程和主线程是随机的运行状态,

ThreadName:testJoin
ThreadName:testJoin
I am main Thread
I am main Thread
I am main Thread
I am main Thread
I am main Thread
I am main Thread
ThreadName:testJoin
ThreadName:testJoin
ThreadName:testJoin

 

 

  写了之后

ThreadName:testJoin
ThreadName:testJoin
ThreadName:testJoin
ThreadName:testJoin
ThreadName:testJoin
I am main Thread
I am main Thread
I am main Thread
I am main Thread
I am main Thread
I am main Thread

yield

在做了大量实验和分析后,哎,先看下代码吧

package thread.cn;

import thread.cn.createThread.CreateThread1;

public class joinAndyield {
    
        
    
    public static class Testyield extends Thread{

        @Override
        public void run() {
            
            for(int i = 1 ; i <= 5 ;i++) {
                System.out.println(getName()+"----"+i+"");
                if(0==i%2) {
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                    
                        e.printStackTrace();
                    }
                    System.out.println("\\\\\\"+getName()+"\\\\");
                    Thread.yield();
                }
            }
            
        }
    }
    
    public static void main(String[] args) throws Exception {
        
        
        Thread t1 = new Testyield();
        Thread t2 = new Testyield();
        t1.start();
        t2.start();
    }
    }
    
Thread-1----1
Thread-0----1
Thread-0----2
Thread-1----2
\\\Thread-0\\
Thread-0----3
Thread-0----4
\\\Thread-1\\
Thread-1----3
Thread-1----4
\\\Thread-0\\
Thread-0----5
\\\Thread-1\\
Thread-1----5

分析可得,yield()之后并不会将线程给另外一个线程,虚拟机做的只是释放当前线程的资源。yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中。

 

对象锁

synchronized:

一个线程A获取了该对象的锁之后,其他线程来访问其他synchronized实例方法现象时,要先A把释放掉后其他线程才能拿到对象锁

package thread.cn;

public class ThreadSy  extends Thread{

      synchronized void show1() {
        System.out.println("show1 start");
        try {
            Thread.sleep(1000);
            System.out.println("show1 is run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("show1 is finally");
        }
    }
     synchronized void show2() {
        System.out.println("show2 start");
        try {
            Thread.sleep(1000);
            System.out.println("show2 is run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("show2 is finally");
        }
    }
    public static void main(String[] args) {
        ThreadSy becomeBt = new ThreadSy();
        Thread t1 = new Thread(becomeBt);
        Thread t2 = new Thread(becomeBt);
        new Thread(t1) {
            public void run(){
                becomeBt.show1();
            }
        }.start();
        new Thread(t2) {
            public void run(){
                becomeBt.show2();
            }
        }.start();
    }
    
}

结果:

show1 start
show1 is run
show1 is finally
show2 start
show2 is run
show2 is finally

 

当访问其他非synchronized实例方法时,无需A释放锁。

 

package thread.cn;

public class ThreadSy  extends Thread{

      synchronized void show1() {
        System.out.println("show1 start");
        try {
            Thread.sleep(1000);
            System.out.println("show1 is run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("show1 is finally");
        }
    }
      void show2() {
        System.out.println("show2 start");
        try {
            Thread.sleep(1000);
            System.out.println("show2 is run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("show2 is finally");
        }
    }
    public static void main(String[] args) {
        ThreadSy becomeBt = new ThreadSy();
        Thread t1 = new Thread(becomeBt);
        Thread t2 = new Thread(becomeBt);
        new Thread(t1) {
            public void run(){
                becomeBt.show1();
            }
        }.start();
        new Thread(t2) {
            public void run(){
                becomeBt.show2();
            }
        }.start();
    }
    
}

 

结果:

show1 start
show2 start
show1 is run
show1 is finally
show2 is run
show2 is finally

 

 

类锁:

 

synchronized作用于一个给定的实例对象instance,即当前实例对象就是锁类对象,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有instance实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,这样也就保证了每次只有一个线程执行i++;操作、

 

package thread.cn;

public class synchronizedTest1 implements Runnable {
    static synchronizedTest1 instance=new synchronizedTest1();
    static int i=0;
    @Override
    public void run() {
        //省略其他耗时操作....
        //使用同步代码块对变量i进行同步操作,锁对象为instance
        synchronized(instance){
            for(int j=0;j<5;j++){
                i++;
                System.out.println(Thread.currentThread().getName()+"-----"+i);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(instance);
        Thread t2=new Thread(instance);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(i);
    }
}


Thread-0-----1
Thread-0-----2
Thread-0-----3
Thread-0-----4
Thread-0-----5
Thread-1-----6
Thread-1-----7
Thread-1-----8
Thread-1-----9
Thread-1-----10
10

 

 

小结:

在对象锁中,若两个线程锁同一个对象,必是先拿到锁的先运行(并不是运行完成所有,但是是先运行),再是另外线程运行。

      若线程锁的是两个毫不相关的对象时,他们是并行关系,可以同时运行。

类锁:类锁和不相干的对象锁同时被线程运行时,他们是并行关系,可以同时运行。

posted @ 2019-05-12 00:27  JustRun1  阅读(173)  评论(0编辑  收藏  举报