多线程

1.start和run方法启动线程

2.创建线程的方式

1.继承Tread类,重写run方法,调用start开启线程

public class Thread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 2000; i++) {
            System.out.println("Run方法执行"+i);
        }
    }

    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();

        //start()方法开启线程
        thread1.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("Start方法开启"+i);
        }
    }
}
  • 部分结果
Start方法开启116
Start方法开启117
Start方法开启118
Run方法执行0
Start方法开启119
Run方法执行1
Run方法执行2
Start方法开启120

2.实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法

public class Thread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 2000; i++) {
            System.out.println("Run方法执行"+i);
        }
    }

    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();

        //start()方法开启线程
        new Thread(thread1).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("Start方法开启"+i);
        }
    }
}

  • 部分结果

    Start方法开启995
    Run方法执行192
    Run方法执行193
    Run方法执行194
    Run方法执行195
    Start方法开启996
    Run方法执行196
    

推荐使用Runnable接口实现,避免单继承局限性,方便同一个对象被多个线程使用

3.Callable接口

import java.util.concurrent.*;

public class Thread1 {


    public static void main(String[] args) throws InterruptedException {

        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());
        new Thread(futureTask).start();

        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    }
     class  MyThread implements Callable<Integer> {

         @Override
         public Integer call() throws Exception {
             System.out.println("Thread");
             return 100;
         }
     }

4.使用线程池

  • JDK 5.0起提供了线程池相关API: ExecutorService 和Executors
  • ExecutorService: 真正的线程池接口。常见子类ThreadPoolExecutor
    • void execute(Rannable command) :执行任务/命令,没有返回值,-般用来执
      行Runnable
    • Future submit(Callable task):执行任务,有返回值,一般又来执行
      Callable
    • void shutdown() :关闭连接池
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

3.join,yield关键字

1.join

Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

public class Thread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 2000; i++) {
            System.out.println("run方法线程"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread1 thread1 = new Thread1();

        Thread thread = new Thread(thread1);

        thread.start();

        for (int i = 0; i < 1000; i++) {
            if(i==200)
                thread.join();

            System.out.println("main"+i);
        }
    }
}

  • 部分结果
main198
main199
run方法线程11
run方法线程12
run方法线程13
run方法线程14
run方法线程15
run方法线程16
run方法线程17
run方法线程18

2.yield

礼让线程,让当前正在执行的线程暂停,但不阻塞

线程从运行状态转为就绪状态

  • 礼让不一定成功
public class Thread1 {

    public static void main(String[] args) throws InterruptedException {
        MyYield myYield = new MyYield();

        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
       }

    }
    class MyYield implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"线程开始执行");
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+"线程停止执行");
        }
}

  • 第一次结果
a线程开始执行
b线程开始执行
a线程停止执行
b线程停止执行
  • 第二次结果
b线程开始执行
a线程开始执行
b线程停止执行
a线程停止执行
  • 第三次结果
a线程开始执行
a线程停止执行
b线程开始执行
b线程停止执行

4.线程状态观测

  • Thread源码
public enum State {
    
    //新生
    NEW,

    //运行
    RUNNABLE,

    //阻塞
    BLOCKED,

    //等待
    WAITING,

    //超时等待(指定时间后停止等待)
    TIMED_WAITING,

    //终止
    TERMINATED;
}

Thread.State

线程状态,线程可以处于以下状态之一:

  • NEW

尚未启动的线程处于此状态

  • RUNNABLE

在Java虚拟机中执行的线程处于此状态

  • BLOCKED

被阻塞等待监视器锁定的线程处于此状态

  • WAITING

正在等待另一个线程执行特定动作的线程处于此状态

  • TIMED_WAITING

正在等待另一个线程执行动作达到指定等待时间的线程处于此状态

  • TERMINATED

已退出的线程处于此状态

一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态

5.线程优先级

  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。

  • 线程的优先级用数字表示,范围从1~10.

    • Thread.MIN_PRIORITY = 1;
    • Thread.MAX_PRIORITY = 10;
    • Thread.NORM_PRIORITY = 5;
  • 使用以下方式改变或获取优先级

    • getPriority() . setPriority(int xxx)

优先级的设定建议在start()调度前

优先级低只是意味着获得调度的概率低.并不是优先级低就不会被调用了.这都是看CPU的调度

6.守护线程

  • 线程分为用户线程和守护线程

  • 虚拟机必须确保用户线程执行完毕

  • 虚拟机不用等待守护线程执行完毕

  • 如,后台记录操作日志,监控内存,垃圾回收等待..

thread.setDaemon(true);

7.线程同步

由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题﹐为了保证数据在方法中被访问时的正确性,在访问时加入锁机制synchronized ,当一个线程获得对象的排它锁,独占资源﹐其他线程必须等待,使用后释放锁即可.存在以下问题:

  • 一个线程持有锁会导致其他所有需要此锁的线程挂起;
  • 在多线程竞争下﹐加锁﹐释放锁会导致比较多的上下文切换和调度延时,引起性能问题﹔
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能问题.

8.synchronized与Lock的对比

  • Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁, 出了
    作用域自动释放
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使甪Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
  • 优先使用顺序:
    • Lock >同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方
      法体之外)
# Java 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×