Java_多线程基础

自定义线程

实现方式

  1. 继承Thread类
  2. 实现Runnable 接口

继承Thread 类

  • 继承Thread后,要重写run 方法
  • public void run 方法体 为该线程要执行的任务
  • 启动线程的方法为start() ,不是调用run()
  • 调用run方法不能开启新的线程,只是普通的函数调用
  • 线程的生命周期类只能被启动一次
    public class xiancheng2 {

    public static void main(String[] args) {
            
        //创建对象
        Myrun  run1 =  new Myrun();
        //创建线程对象
        Thread  runTd = new Thread( run1 );
        // 开启线程
        runTd.start();
        run1.say();
    }
}

class Myrun extends Thread{
    @Override
    public void run() {
        System.out.println("新的线程");
    }
    
    public void say() {
        System.out.println( "美好的一天" );
    }
    
}

常用API

String getName() 返回该线程的名称。
long getId() 返回该线程的标识符。
int getPriority() 返回线程的优先级。
Thread.State getState() 返回该线程的状态。
join() 等待该线程终止。
join( long millis ) 等待该线程终止的时间最长为 millis 毫秒。
static void sleep(long millis ) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
void start()
void interrupt() 中断线程。
static boolean interrupted() 测试当前线程是否已经中断。
boolean isDaemon() 测试该线程是否为守护线程。

实现Runnable 接口

  • 方法与继承Tread 类似即:

    • 继承Runnable 接口,实现run 方法
    • 创建线程对象 , 开启线程

差异

  1. 通过接口的方式,更加灵活(Java是单继承)
  2. 继承的方式更加简单。(使用较少)

线程状态

  1. 一个线程一般要经历5个状态
    • 新建状态
    • 准备状态
    • 运行状态
    • 等待/阻塞状态
      • 睡眠 : 调用sleep()
      • 阻塞 :
      • 挂起 : 调用suspend 挂起,resume()解除挂起 ( 不建议使用)
      • 等待 : 调用 wait()
    • 死亡状态

线程的使用

睡眠

  • 调用sleep方法可以让线程睡眠指定的时间后再苏醒进入准备状态,

    • public static void sleep( long millis) throw InterruptedException

    • public static void sleep( long millis , int nanos) throw InterruptedException

public class xiancheng2 {
    public static void main(String[] args) throws InterruptedException{
            
        //创建对象
        Myrun  run1 =  new Myrun();
        //创建线程对象
        Thread  runTd = new Thread( run1 );
        Thread  runTd2 = new Thread( run1 );
//       开启线程
        runTd.start();
        //使主线程睡眠100ms
        Thread.sleep(100);  
        System.out.println( "美好的一天" );
    }
}

class Myrun implements Runnable{
    
    @Override
    public void run() {
        System.out.println("新的线程");
        try {
            // 使该线程睡眠100ms
            Thread.sleep(100);  
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

线程的优先级

  • Java中线程的优先级用1~10之间的整数表示。值越大,优先级越高。默认为5
  • 不适合对线程进行细节调节

  • 主线程的优先级默认为5。子线程优先级初始值与父线程相同。

  • 改变优先级:(不能精确)

    • public final void setPriority( int newPriority )

public class xiancheng2 {
    public static void main(String[] args) {
            
        //创建对象
        Myrun  run1 =  new Myrun(1);
        Myrun  run2 =  new Myrun(2);
        //创建线程对象
        Thread  runTd1 = new Thread( run1 );
        Thread  runTd2 = new Thread( run2 );
        //设置优先级
        runTd2.setPriority( Thread.MIN_PRIORITY );//最高的优先级
        runTd1.setPriority( Thread.MAX_PRIORITY );//最低的优先级
        //开启线程
        
        runTd2.start();
        
        runTd1.start();
        
    }
}
class Myrun implements Runnable{
    private  int id ;
    public Myrun(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        System.out.println("新的线程"+ this.id);
    }
    
}

线程的让步

  1. 分类
    • 线程只是让出当前的CPU资源,具体将CPU让给谁不能确定 (无保障)
    • 线程将给指定的线程让步,指定的线程没有完成,其绝不恢复执行 (线程合并--有保障)
  2. yield方法

    • 使当前正在运行的线程让出CPU,回到准备状态。(无保障)

      • pubic static void yield()

  3. join方法

  • 调用join方法的线程将执行完,后再恢复其他线程执行

    • public final void join( ) throw InterruptedException

    • public final void join( long millis) throw InterruptedException

    • public final void join( long millis ,int nanos ) throw InterruptedException

public class xiancheng2 {
    public static void main(String[] args) throws InterruptedException{
            
        Thread  run1 =  new Myrun("先");
        Thread  run2 =  new Myrun("后");
        
        run2.start();
        run2.join();    //run2线程将执行完后,在恢复其他线程。
        
        run1.start();
        for (int i = 0; i < 50; i++) {  
            System.out.print(6);
        }
    }
}
class Myrun extends Thread{
    private  String id ;
    public Myrun(String id) {
        this.id = id;
    }
    @Override
    public void run() {
        try {
            
        } catch (Exception e) {
            // TODO: handle exception
        }
        for(int  i=100 ;i>0;i--) {
            System.out.print(this.id);
        }
    }
}   

注意(有参)



如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。
需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。                     
                                                                            摘自:https://www.cnblogs.com/ldq2016/p/9045551.html

线程守护

  • 在后台运行的线程(内存管理,线程调度...) 称之为守护线程
  1. 开发守护线程

    • public final void setDaemon( boolean on ) // on表示是否设置为守护线程(fal se:普通线程)

      • java中 : 但前台线程(普通线程)都运行结束后,程序退出
        • 与回台程序是否运行完无关。

同步线程

同步方法

  • 同步方法是指用synchronized修饰的方法

    • synchronized <返回类型> 方法名 ([参数列表])[throw 异常]{

      }

      • 静态的同步方法的锁对象为 : 当前的class的对象
      • 非静态的同步方法的锁对象为 :this
      • 当线程获得锁锁后进入睡眠或让步,将带着锁一起睡眠,让步。
      • 同步方法退出后,锁将被释放,等待其他的线程可以获取锁。
      • 同步将会降低多线程的并发性。
public class tridet {

    public static void main(String[] args) {
        
        Ticket tck = new Ticket();
        Thread t2 = new Thread(tck,"window1");
        Thread t1 = new Thread(tck,"window2");
        Thread t3 = new Thread(tck,"window3");
        System.out.println( "tck: " + tck );
        t1.start();
        t2.start();
        t3.start();
    }
}

class Ticket implements Runnable{
    private  int  TicketNum = 100;
    
    public void run() {
        while( this.TicketNum>0 ) {
            this.buy();
        }
    }
    
    public synchronized void buy() {
        System.out.println( this );  // this ==> tck(锁对象)
        if(this.TicketNum-->0) 
            System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum   );
    }
}

同步调度方法

final void wait() 使某个线程进入等待状态。直到别的线程调用notify或notifyAll方法将其唤醒
final void wait(long timeout) timeout 毫秒数,使某个线程进入等待状态,直至达到等待时间,或将其唤醒为止。
final void notify() 唤醒等待池中的某一个线程(没有保障,不能确定唤醒哪一个线程)
final void notifyAll() 唤醒等待池中的所有线程

同步语句块

synchronized (锁对象){ }

  • 锁对象要唯一
    • 锁对象就如同一个保管钥匙的人,要使保证同步那么就要保证只有当一个线程执行完了同步语句块后(归还钥匙)其他的线程才能进入同步语句块,所有保管钥匙的人要唯一(钥匙只有一把)。
public class tridet {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Thread t2 = new Ticket("window2");
        Thread t1 = new Ticket("window1");
        Thread t3 = new Ticket("window3");
        t1.start();
        t2.start();
        t3.start();
        
    }
}

class Ticket extends Thread{
    private static int  TicketNum = 10;
    private static Object  look = new Object(); // 锁对象(唯一)
    
    public void run() {
        while( this.TicketNum > 0 ) {
            synchronized (look) {
                if(this.TicketNum--<=0) break;
                System.out.println(getName() + "买出一张票,还剩:" + this.TicketNum   );
            }   
        }
    }
    
    public Ticket(String name) {
        super(name);
    }
}

public class tridet {

    public static void main(String[] args) {
        
        Ticket tck = new Ticket();
        
        Thread t2 = new Thread(tck,"window1");
        Thread t1 = new Thread(tck,"window2");
        Thread t3 = new Thread(tck,"window3");
        t1.start();
        t2.start();
        t3.start();
        
    }
}

class Ticket implements Runnable{
    private  int  TicketNum = 100;
    
    public void run() {
        while( this.TicketNum > 0 ) {
            synchronized (this) {   //锁对象为this , 即:tck对象(唯一)
                if(this.TicketNum--<=0) break;
                System.out.println(Thread.currentThread().getName() + "买出一张票,还剩:" + this.TicketNum   );
            }   
        }
    }
}

死锁

  • 相互等待对方释放资源的对象的 锁。

public class shisuo {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Object oj1 = new Object();
        Object oj2 = new Object();
        
        boy b1 = new boy( oj1 , oj2 );
        girl g1 = new girl( oj1 , oj2 );
        
        Thread thread1 = new Thread(b1,"boy");
        Thread thread2 = new Thread(g1,"boy");
        
        thread1.start();
        thread2.start();
    }
}

class boy implements Runnable {
    private Object look1, look2;
    public boy(Object look1, Object look2) {
        super();
        this.look1 = look1;
        this.look2 = look2;
    }
    public void run() {
        synchronized (look1) {
            System.out.println("body");
            synchronized (look2) {
                System.out.println("body2");
            }
        }
    }
}

class girl implements Runnable {
    private Object look1, look2;
    public girl(Object look1, Object look2) {
        super();
        this.look1 = look1;
        this.look2 = look2;
    }
    public void run() {
        synchronized (look2) {
            System.out.println("girl");
            synchronized (look1) {
                System.out.println("girl2");
            }
        }
    }
}

volatile 关键字

  • 作用:被其修饰的成员变量不允许一个线程对其操作过程中,其他线程插入操作。

  • 该关键字只允许修饰成员变量 , 不能修饰局部变量。
    • 局部变量不可能同时被两个线程

猜你喜欢

转载自www.cnblogs.com/zoukun/p/12275832.html