欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Java】java多线程

程序员文章站 2022-05-05 21:45:23
...

线程基本概念
线程是什么?
一个线程就是一个程序内部的一条执行路径,一个进程可以包含多个进程。
当程序启动运行时,就自动产生了一个线程,主函数main就是在这个线程上运行的,当不再产生新的线程时,程序就是单线程,只有一条执行路径。

进程是什么?
计算机中的程序关于某数据集合上的一次运行活动。可以理解成每个独立运行的程序就是一个进程,进程也就是“正在运行的程序”。

线程和进程的区别:
每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,线程可以看成是轻量级的进程,同一线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程的切换开销小。

什么是多进程:
在操作系统中同时执行多个程序

什么是多线程:
在同一个应用程序中有多个执行路径,但是在一个时间点上,只用一个线程在该CPU 上运行。

多线程的创建和启动
创建多线程有两种方法:继承Thread类和实现Runnable 接口

使用Thread类创建多线程
Thread 类是java 中一个线程类,线程可以通过继承java.lang.Thread的类来实现。
java 程序在启动时由一个主方法main{}创建了一个线程,我们称之为主线程。
我们可以通过创建Thread的实例来创建线程,必须通过调用Thread 类的start方法启动一个线程,

public class A { 
   public static void main(String[] args) {  
        B b=new B();        
        b.start();        
        while(true)     
        {         
            System.out.println("main thread is running.");    
        }   
    }  
}   

class B extends Thread {  
       public void run()  
       {   
          while(true)   
          {                                                      System.out.println(Thread.currentThread().getName()+" is running.");    
          }   
       }  
    }

thread 类有一个start方法,该方法为线程启动,会去执行继承Thread类的run 方法。
要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类。

一个thread类的对象就代表一个线程,而且只能代表一个线程

使用Runnable 接口创建多线程
Runnable接口有一个run()方法,用于定义线程运行体,所以我们只需要重写这个方法就可以。

public class A { 
   public static void main(String[] args) {  
        B b=new B();        
        Thread t=new Thread(b);   //创建一个线程,b为Runnable 接口对象
         //线程启动,会去调用run方法,不能直接调用run方法,那不是启动新线程,而是方法调用
        t.start();        
        while(true)     
        {         
            System.out.println("main thread is running.");    
        }   
    }  
}   

class B implements Runnable {  
       public void run()  
       {   
          while(true)   
          {                                                      System.out.println(Thread.currentThread().getName()+" is running.");    
          }   
       }  
    }

线程的状态控制
当我们的线程被new出来的时候只是一个对象,当我们调用start 的方法时,就进入就绪状态,当被调度到cpu的时候才进入运行状态,在运行的过程中如果突发事件导致阻塞,则进入阻塞状态,阻塞解除之后进入就绪状态,线程只能从就绪态到运行状态。
【Java】java多线程

线程控制的基本方法:
isAlive():判断线程是否还活着,即线程是否还未终止
getPriority():获得线程的优先级数值。
setPriority():设置线程的优先级数值。
Thread.sleep():当前线程睡眠指定毫秒数
join:合并某线程
yield:让出cpu,当前线程进入就绪队列等待调度。
wait() :当前线程进入对象的wait pool中
notify()/notifyAll():唤醒对象的wait pool中的一个/所有等待线程。

sleep:
public static void sleep(long millis) throws interruptedException

 public class TestInterrupt{
     public static void main(String[] args){
       MyThread thread=new MyThread();
       thread.start();
       try{Thread.sleep(100000);}
       catch(InterruptedException e){}
       thread.interrupt();  //打断
}
}

class MyThread extends Thread{

}

线程同步
多个线程之间访问同一份资源的时候,只能有一个线程访问该资源,其他线程都不可以对该资源进行访问,直到该线程结束, 其他线程才能访问该资源。

没有使用锁的代码:

public class TT implements Runnable{
    int b=100;

    public synchronized void m1() throws Exception{
        b=1000;
        Thread.sleep(5000);
        System.out.println("b="+b);
    }
    public void m2() throws Exception{
       Thread.sleep(2500);
       b=2000;
    } 

    public void run(){
          try{
             m1();
       }catch(Exception e){
        e.printStackTrace();
       }
     }

     public static void main(String[] args) throws Exception{
         TT tt=new TT();
         Thread t=new Thread(tt);
         t.start();

         Thread.sleep(1000);
         tt.m2();
     }
}

当前程序有两个线程对象,一个主线程,一个t.start线程,当执行t.strat()时候,t线程会去执行m1,t1线程获得了这把锁,此时b=1000,其他线程不能再来执行这个方法,但是其他线程可以去执行别的方法,在t1睡眠5秒时,tt线程去执行m2 方法,此时b=2000,然后t线程再去打印b, 再去所有打印出来的b是2000。

假如给m2 方法也加上锁,如下

public class TT implements Runnable{
 int b=100;

 public synchronized void m1() throws Exception{
    b=1000;
    Thread.sleep(5000);
    System.out.println("b="+b);
}
public synchronized void m2() throws Exception{
   Thread.sleep(2500);
   b=2000;
} 

public void run(){
      try{
         m1();
   }catch(Exception e){
    e.printStackTrace();
   }
 }

 public static void main(String[] args) throws Exception{
     TT tt=new TT();
     Thread t=new Thread(tt);
     t.start();

     Thread.sleep(1000);
     tt.m2();
 }
}

本程序有两个线程,首先是t调用m1方法,给对象加锁,此时tt不能再为该对象加锁,只能等待t执行完,才能对m2加锁,执行m2的方法,某一对象在某一时刻只能被一个线程加锁, synchronized 锁定当前对象,某一时刻只能锁定当前对象的一个方法,另外一个加锁的方法不能再去锁定当前对象。每一个对象只有一把锁,谁拿到这把锁谁就执行该方法,其他的对象不能拿到该对象的这把锁。