Java 多线程

一、进程 / 线程

进程:启动一个application,就调度了一个进程,CPU分配内存

线程:进程中的一部分,相当于进程中的一条路径,多线程,就是多条路径。线程资源共享,CPU不额外分配内存

 

二、Java实现多线程

1、 继承Thread,重写run方法

/**
 1. 创建多线程,继承Thread,重写run()方法
 2. 使用线程:创建子对象 + 对象.start(),线程启动
 */
public class Rabbit extends Thread {
    @Override
    public void run() {
        //线程体
        for (int i = 0; i <= 20; i++) {
            System.out.println("Rabbit has run " + i + " steps.");
        }
    }
}

   class Turtle extends Thread {
        @Override
        public void run() {
            for (int i = 0; i <= 5; i++) {
                System.out.println("Turtle has run " + i + " steps.");
            }
        }
    }

public class Main {

    public static void main(String[] args) {

        Rabbit rabbit = new Rabbit();
        Turtle turtle = new Turtle();

        rabbit.start();     //调用start方法,系统会自动调用run方法,不要直接调用run方法
        turtle.start();     //这样就有两条路径了
    }
}

 

2、实现Runnable接口 + 重写run()方法

/**
 推荐使用Runnable接口
 1、避免Thread单继承的问题
 2、方便资源共享
 */
public class Traveler implements Runnable {

    private int numberoftickets = 20;

    @Override
    public void run() {
        while (true){
            if (numberoftickets<0){
                break;
            }
            System.out.println(Thread.currentThread().getName() + " 抢到了 " + numberoftickets--);
        }
    }

    public static void main(String[] args) {
        //真实角色 - traveller
        Traveler traveler = new Traveler();
        //代理 - Thread
        Thread t1 = new Thread(traveler, "黄牛1号");
        Thread t2 = new Thread(traveler, "黄牛2号");
        Thread t3 = new Thread(traveler, "黄牛3号");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

 

3、实现callable接口 + 重写call 

这个方法实现起来较复杂

优点:

  • 可以抛出异常
  • 可以返回值

 

三、线程的状态和停止线程

public class TestDemo  {

    public static void main(String[] args) {

        Study s = new Study();
        new Thread(s).start();

        //外部干涉
        for (int i = 0; i<20; i++){
            if (i==10){
                s.stop();
            }
            System.out.println("I'm taking break..." + i);
        }
    }
}


class Study implements Runnable{

    //1、线程类中,定义线程体使用的标示
    private boolean flag = true;

    @Override
    public void run() {
        //2、线程体使用该标示
        while (flag){
            System.out.println("I'm studying..." );
        }
    }

    //3、对外提供方法改变标示
    public void stop(){
        flag = false;
    }
}

//尽量不要调用Thread.stop()方法,而是自己写一个外部干涉
//或者让线程体运行完自然停止

 

四、线程阻塞

1、join,合并线程,被合并的线程需要等去合并的线程执行完,所以被合并的线程阻塞

2、yeild,static,暂停当前正在进行的线程,执行其他线程

3、sleep,休眠,暂停当前线程,不会释放锁。 

  • 常用于与时间相关:ex: 倒计时
  • 网络延时
/**
 * 倒计时10秒
 */

public class SleepDemo {
    public static void main(String[] args) throws InterruptedException {
        Date endTime = new Date(System.currentTimeMillis()+10*1000);
        long end = endTime.getTime();
        while (true){
            //输出
            System.out.println(new SimpleDateFormat("mm:ss").format(endTime));
            //构建下一秒的时间
            endTime = new Date(endTime.getTime() - 1000);
            //等待1秒
            Thread.sleep(1000);
            //10秒以内继续输出,否则break
            if (end - 10000 > endTime.getTime()){
                break;
            }
        }
    }
}

 

五、线程的基本信息

  • Thread.currentThread()
  • setName()
  • getName()
  • isAlive, 返回true/false

优先级:

  • MAX_PRIORITY 10
  • NORMALLY_PRIORITY 5
  • MIN_PRIORITY 1

Thread.setPriority //设置优先级 (优先级不代表先后顺序,而代表概率。)

 

六、线程同步与锁定

同步:也称为并发,多个线程访问同一份资源,要确保资源安全

关键字:synchronized

/**
 * 懒汉式
 */
public class TestDemo {
    private static TestDemo instance;           //1、声明一个私有化的静态属性
    private TestDemo(){                         //2、私有化构造器

    }
    public static TestDemo getInstance(){       //3、声明公共的访问方法,来访问此静态属性
        if (instance==null){    //第一层判断,提供效率
            synchronized (TestDemo.class){
                if (instance==null){    //第二层判断,确保线程安全
                    instance = new TestDemo();
                }
            }
        }
        return instance;
    }
}
/**
 * 饿汉式
 */
public class TestDemo {
    private static class TestDemoInner {
        private static TestDemo instance = new TestDemo();    //1、直接内部先私有化一个对象(饿嘛)
    }   
     //把这个私有属性放进一个内部类,主要是为了效率,否则TestDemo类一加载,这个私有属性就会被初始化, //而放在内部类中,只有加载get方法,才会初始化
   private TestDemo(){ //2、私有化构造器 } public static TestDemo getInstance(){ //3、声明公共的访问方法,返回的是内部类.instance return TestDemoInner.instance; } }

 

 

与sychronized可以一起使用的两个方法:wait() ,  notify() / notifyAll()

生产者消费者模式 (信号灯法):其中一个线程生产,另一个wait,生产完毕之后notify,另一个开始消费,有效避免死锁。

 

线程任务调度:

Timer()

Timer.schedule(TimerTask task, Date time)

Timer.schedule(TimerTask task, Date firstTime, long period)

 

posted on 2018-09-13 17:33  TheExile  阅读(178)  评论(0)    收藏  举报

导航