【Java学习】创建线程3种方式和获取线程池(24)


创建线程三种方式

方式一:
定义一个类,继承Thread类,重写其中的run方法,
在主方法中创建你定义的这个类的对象,调用start()方法

定义的线程类:

package com.jingfei.homework;

public class Mythread extends Thread {
    @Override
    public void run() {
        System.out.println(this.getName()+"创建的线程执行了");
    }
}

主类:

package com.jingfei.homework;

public class Demo1 {
    public static void main(String[] args) {
//创建线程的三种方式
        Mythread mythread = new Mythread();
        Mythread mythread1 = new Mythread();
        mythread.setName("线程1");
        mythread1.setName("线程2");
        //mythread.run();//注意直接调用run方法是不能开启线程,只是调用run方法而已.
        System.out.println("---------------");
        mythread.start();// 必须调用start()由底层调用run方法才会开启线程.
        mythread1.start();

    }
}


方式二:

定义一个类,实现Runnable接口,重写run方法,
在主方法中,创建接口的子类对象,创建Thread对象,然后把接口的子类对象,作为参数传给Thread
再调用start()方法开启线程

定义的类实现Runnable接口:

package com.jingfei.homework;

public class Mythread2 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"创建的子线程执行了");
    }
}

主类:

package com.jingfei.homework;

public class Demo2 {
    public static void main(String[] args) {
        Mythread2 mythread2 = new Mythread2();
        Thread thread = new Thread(mythread2, "线程1");//可以直接传入线程名字
        Thread thread1 = new Thread(mythread2);
        thread1.setName("线程2");
        thread.start();
        thread1.start();
    }
}


既然是接口,当然也可以用匿名内部类来获取子类对象

package com.jingfei.homework;

public class Demo21 {
    //既然是需要一个Runnable接口,那可以用匿名内部类
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"创建的子线程执行了");
            }
        };
        Thread thread = new Thread(r);
        thread.setName("线程1");
        Thread thread1 = new Thread(r);
        thread1.setName("线程2");
        thread.start();
        thread1.start();
    }
}


方式三:
这种方法可以带回线程的返回值

定义一个类实现Callable接口,重回call方法,创建一个 FutureTask<> 这个类,把Callable接口的子类对象传给他,创建Thread类 然后把FutureTask的对象传给Thread 最后开启线程,

创建一个类实现Callable接口:

package com.jingfei.homework;

import java.util.concurrent.Callable;

public class MyThread3 implements Callable {
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"创建的子线程执行了");
        return 100;//必须由返回值,这是这种开启线程独有的
    }
}

主类:

package com.jingfei.homework;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread3 myThread3 = new MyThread3();
        FutureTask ft1 = new FutureTask(myThread3);
        Thread thread1 = new Thread(ft1,"线程1");
        FutureTask ft2 = new FutureTask(myThread3);
        Thread thread2 = new Thread(ft2,"线程2");
        //thread2.setName("线程2");
        thread1.start();
        thread2.start();
        Integer integer1 = ft1.get();
        System.out.println("线程1的返回值"+integer1);
        Integer integer2 = ft2.get();
        System.out.println("线程2的返回值"+integer2);

    }
}

既然是接口,当然也可以用匿名内部类来实现

package com.jingfei.homework;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Demo31 {
    public static void main(String[] args) {
        Callable callable = new Callable() {
            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName() + "创建的子线程执行了");
                return 100;
            }
        };
        FutureTask ft = new FutureTask<>(callable);
        FutureTask ft1 = new FutureTask<>(callable);
        //FutureTask是Java实现了Runnable的子类,可以用来封装Callable任务
        Thread thread = new Thread(ft);
        Thread thread1 = new Thread(ft1);
        thread.setName("线程一");
        thread1.setName("线程二");
        thread.start();
        thread1.start();

    }
}


线程中的一些方法,控制线程
线程加入jion(),加入的线程优先执行,其他线程互相争抢cpu
设置守护线程setDaemon(true) ,主线程死亡后,守护线程会立即死亡
获取和设置优先级getPriority(),setPriority() [1,10],1最小,10最大,
线程休眠sleep(),让线程阻塞,但是线程并不释放当前已经拥有的资源
线程礼让yield() (不一定一人一次执行,还是争抢cpu)
中断线程interrupted() 打断线程的阻塞状态
强制停止线程 stop(),使线程死亡

线程安全的问题,得满足三个条件:
1.是否是多线程环境
2.是否还有共享数据
3.是否有多条语句在操作这个共享数据
如果出现线程安全问题,我们用同步来解决

同步代码块
        synchronized (锁对象){
            //包裹你可能出现数据安全问题的代码
        }
        
同步方法
        public synchronized void test(){
            //包裹你可能出现数据安全问题的代码
        }

锁对象:
同步代码块使用的锁对象,是任意锁对象,(不同对象要想互斥访问,必须用同一个锁对象)
同步方法使用的锁对象 是this
静态同步方法使用锁对象是 当前类的字节码文件对象 .class


获取线程池

线程池:是一个容器,里面预先装有线程对象,并可以帮我们高效的管理线程对象

我们自己手动创建线程,是比较耗费底层资源的,而且这个线程使用完之后,就死亡了,不能重复利用
JDK1.5之后,获取线程池对象,Java给我们提供了一个工厂,用这个工厂类,来来获取线程池对象
新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newCachedThreadPool ():根据任务的数量来创建线程对应的线程个数
public static ExecutorService newFixedThreadPool ( int nThreads):固定初始化几个线程
public static ExecutorService newSingleThreadExecutor ():初始化一个线程的线程池

代码示例

package com.jingfei.homework;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo4 {
    public static void main(String[] args) {
        ExecutorService pool1 = Executors.newCachedThreadPool();
        ExecutorService pool2 = Executors.newFixedThreadPool(2);//固定2个
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "pool1中创建的子线程执行了");
            }
        };
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "pool2中创建的子线程执行了");
            }
        };
        //向线程池pool1中提交任务,线程池根据任务的多少创建多少个子线程,直到任务全部完成,子线程就会处于等待状态,不会死亡
        /*pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.submit(runnable);
        pool1.shutdown();*/

        //向线程池pool2中提交任务,线程池固定了只能有2个子线程,所以这两个子线程互相争抢任务执行,执行完成后,继续争抢,直到任务全部完成,子线程就会处于等待状态,不会死亡.
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.submit(runnable2);
        pool2.shutdown();
    }
}


谢谢!

你可能感兴趣的:(初学Java)