Programmer Log16[多线程1]_19.12.09

1.四种实现多线程的方法
1.1 继承Thread类实现多线程
java.lang.Thread是一个线程操作的核心类。新建一个线程最简单的方法是继承Thread类,而后覆写该类中的run()方法

class MyThread extends Thread{
    private String title;
    public MyThread(String title){
        this.title = title;
    }
    public void run(){
        for(int i=0;i<10;i++){
                System.out.println(this.title+",i="+i);
        }
    }
}

//效果是三个线程交错执行

public class TestDemo{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread("thread1");
        MyThread myThread2 = new MyThread("thread2");
        MyThread myThread3 = new MyThread("thread3");
        myThread1.start();//public synchronized void start() 
        myThread2.start();//这个方法是启动多线程的方法
        myThread3.start();//会自动调用run()方法
    }
}

深入剖析一下一个线程是如何运行的:在start()方法中,会调用start0()方法,start0()是一个本机的原生系统函数。Thread类有个registerNatives本地方法,该方法就是注册一些本地方法供Thread类使用,如start0(),stop0()等。而registerNatives()方法放在一个static块中,当Thread类被加载时就会被调用。而本地方法registerNatives是定义在Thread.c文件中的(Thread.c中定义了各个操作系统平台都要用到的关于线程的公用数据和操作),至于怎么调用到run()方法(这个我还没有看懂…)
Tips:native指的是调用本机的原生系统函数
1.2 Runnable()接口实现多线程
为了打破单继承局限,用实现Runnable()接口来代替继承Thread类
Runnable()接口里有run()方法,但是多线程的启动必须由Thread方法来完成,所以在这种实现方法里要通过创造Thread类的匿名对象来进行start()方法的调用。

class MyRunnable implements Runnable { // 线程主体
    private String title ;
    public MyRunnable (String title) {
    this.title = title;
    }
    @Override
    public void run() { // 所有线程从此处开始执⾏
    for (int i = 0; i < 10 ; i++) {
    System.out.println(this.title+",i = " + i);
    }
  }
}

Thread类提供的构造方法:

public Thread(Runnable target)


public class TestDemo{
    public static void main(String[] args){
        MyThread mythread1 = new MyRunnable ("thread1");
        MyThread mythread2 = new MyRunnable ("thread2");
        MyThread mythread3 = new MyRunnable 
        ("thread3");
        new Thread(mythread1).start();//新建Thread类的对象来调用start()方法启动多线程
        new Thread(mythread2).start();
        new Thread(mythread3).start();
    }
}

1.2.1 使用匿名内部类实现

public class TestDemo{
    public static void main(String[] args){
        new Thread(new Runnable(){
            public void run(){
                System.out.println("Hello World");
            }
        }).start();
    }
}

1.2.2 使用Lamdba表达式进行Runnable对象创建

public class TestDemo{
    public static void main(String[] args){
        Runnable runnable = ()->System.out.println("Hello World");
        new Thread(runnable).start();
    }
}

Tips:Thread类实现了Runnable接口,实际上使用Runnable实现多线程是一个代理模式,Thread是资源调度的类,MyThread才是核心业务类。
使用Runnable能实现资源共享(比如卖票程序)
//多个线程卖同一批票,如果用Thread类实现的话就变成了各自卖各自的票

class MyThread implements Runnable {
    private int ticket = 10 ; // ⼀共10张票  
     @Override
    public void run() {
    while(this.ticket>0){ 
    System.out.println("剩余票数:"+this.ticket -- );
    }
}
}
public class TestDemo {
    public static void main(String[] args) {
    MyThread mt = new MyThread();
    new Thread(mt).start();
    new Thread(mt).start();
    }
}

1.3 Callable实现多线程
JDK1.5追加的新的开发包 java.uti.concurrent,主要在进行高并发编程时使用。包中有个接口是Callable
用Callable实现多线程的应用场景:Runnable接口里的run()方法没有返回值,但有些线程可能需要返回值,这时候就由Callable接口里的call()方法来实现
具体实现:

class MyCallable implements Callable<String> {
    private int ticket = 10 ; // ⼀共10张票  
     @Override
    public String call() throws Exception {
    while(this.ticket>0){ 
    System.out.println("剩余票数:"+this.ticket -- );
    }
    return "执行完成";
}
}
public class TestDemo{
    public static void main(String[] args){
        //FutureTask类间接实现了Runnable接口,可以作为Thread类的构造方法的参数
        //此类的构造方法接收Callable接口的实例化对象,MyThread类实现了Callable接口
        //因为只有Thread类的实例能调用start(),所以起承转Thread(......)
        FutureTask<String> task = new FutureTask<String>(new MyCallable());
        new Thread(task).start();
        new Thread(task).start();
        System.out.println(task.get());
    }
}

1.4 线程池(常用)

public static void main(String args[]}){
    //1.使用工具类获取线程池对象
        ExecutorService executorService=Executors.newFixedThreadPool(10);
    //2.通过线程池对象获取线程并执行MyRunnable实例
        ececutorService.execute(new MyRunnable());
        
}

扩展:每次运行程序至少启动两个线程,一个是main线程,一个是垃圾收集线程

2.多线程的常用操作方法
由于多线程的运行状态不确定,所以对于多线程要有一个能明显标识出线程对象的信息,也就是线程名称

public Thread(Runnable target,String name)//创建线程的时候设置名称
public final synchronized void setName(String name);//设置线程名称
public final String getName();//取得线程名称
public static native Thread currentThread();//取得当前线程对象
用法:
public class TestDemoThread{
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt).start();
        new Thread(mt).start();
        new Thread(mt,"stay").start();
    }
}

class  MyThread implements Runnable{
    public void run(){
        for(int i =0;i<10;i++){
            System.out.println("当前线程"+Thread.currentThread().getName()+" i= "+i);
        }
    }
}

public static native void sleep(long millis) throws InterruptedException;
线程休眠方法,休眠时间使用毫秒作为单位,使线程进入阻塞态。交出CPU但不会释放锁,也就是说如果这个线程持有某个对象的锁,即使sleep了其他线程也无法访问这个对象

public static native void yield();

线程让步方法,暂停当前执行的线程,使线程进入就绪态并执行其他线程。交出CPU权限但不会释放锁。与sleep不同的是yield不能控制具体的交出CPU的时间,而且yield只能让拥有相同优先级的线程有获得CPU的机会

public final synchronized void join(long millis)

在主线程中调用此方法会让主线程休眠,让 调用该方法的线程的run方法执行完毕,再执行主线程
//运行结果保证“代码结束”在最后出现
//如果注掉thread.join(),则“代码结束”的运行顺序可能在线程A前

public class TestDemoThread2{
    public static void main(String[] args) throws InterruptedException {
        MyThread2 mt = new MyThread2();
        Thread thread = new Thread(mt,"子线程A");
        thread.start();
        System.out.println(Thread.currentThread().getName());
        thread.join();
        System.out.println("代码结束");
    }
    public static void printTime(){
        Date date = new Date();
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        System.out.println(time);

    }
}
class  MyThread2 implements Runnable{
    public void run(){
        try{
            System.out.println("主线程睡眠前的时间");
            TestDemoThread2.printTime();
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName());
            System.out.println("睡眠结束时间");
            TestDemoThread2.printTime();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值