继承Thread类
构造一个内部类,继承thread类,然后重写run()方法。
如果需要用到共享数据,那么必须是静态属性;
举例:
class MyThread extends Thread{
@Override
/*
重写run方法是为了让这个线程执行这个类的特殊任务;
*/
public void run() {
super.run();
for (int i = 0; i < 100; i++) {
try {
sleep(1000);//等待1000秒后,在CPU分配到资源后,再执行线程
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i % 2 == 0) System.out.println(getName()+i);//
// Thread.currentThread().getName(),会给这个线程起一个默认的名字,不同线程名字不一样
if(i % 20 == 0) yield();//这个方法是为了给其他线程让步,即到了20的倍数时,执行其他线程
getPriority();//获得线程的优先级
setPriority(MAX_PRIORITY);//设置线程的优先级,优先级高更高的概率执行,但不一定就是先执行。
}
}
public MyThread(String name){
super(name);
}
public MyThread(){
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setName("线程一");//要放在start()方法前
t1.start();//只能用start()方法,如果用run()启动,就不是多线程了。start方法的两个功能:启动线程;启动run()方法。
MyThread t2 = new MyThread();//只能新建一个对象来创建另一个线程,不然会报错
t2.start();
Thread.currentThread().setName("主线程");//这是给主线程命名
for (int i = 0; i < 100; i++) {
if(i % 2 != 0) System.out.println(Thread.currentThread().getName()+i);//
// Thread.currentThread().getName(),会给这个线程起一个默认的名字,不同线程名字不一样
if(i % 9 == 0) {
try {
t1.join();//主线程进入阻塞状态,执行t1线程,直到t1执行完才会继续执行主线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(t1.isAlive());//判断线程生命周期是否结束
}
}
}
实现runnable接口
过程:
1.创建一个类实现runnable接口;
2.创建这个类的对象;
3.把这个对象作为参数,新建一个Thread类的对象;
4.用start方法启动
相比方式1的优点:
1.避免由于Java单继承特点导致的局限
2.更适合处理多个线程需要共同变量的情形。
与方式1的共同点:
1.thread类也是实现了runnable接口;
2.都需要重写run方法,把要执行的逻辑写进去。
举例:
public class RunnableTest implements Runnable{
@Override
public void run() {
}
public static void main(String[] args) {
RunnableTest thread = new RunnableTest();
Thread t1 = new Thread(thread);
Thread t2 = new Thread(thread);
t1.start();//因为Thread类的run方法规定,如果构造器传入runnable对象target且不为空,那么就调用target的run方法。
}
}`
实现Callable接口
步骤:
- 创建Callable接口的实现类;
2 .重写call()方法; - 使用时创建实现类的对象;
- 将此对象作为参数传入FutureTask的构造器中并创建对象;
- 将FutureTask的对象作为参数传入Thread类的构造器;FutureTask是Runnable接口的实现类和Future接口的唯一实现类
- 如果想要获得call()方法的返回值,可以使用FutureTask的get()方法。
call() 相比run()的优点:
1.有返回结果;
2.call()可以抛异常,被外面的方法捕获异常信息;
3.call()支持泛型;
举例:
class Sum implements Callable{
@Override
public Object call() throws Exception {
int sums = 0;
for (int i=0; i<=50; i++){
if(sums % 10 ==0) System.out.println("和:"+sums);
sums+=i;
}
return sums;
}
}
public class CallableTest {
public static void main(String[] args) {
Sum s = new Sum();
FutureTask ft = new FutureTask(s);
new Thread(ft).start();
try {
Object sum = ft.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
线程池
线程池把几个线程放在一起,使用的时候从线程池里取出线程,不用的时候还回去,而不像其他方式那样直接销毁对象。
接口:
ExceutorService:真正的线程池接口,excute()用于runnable接口的实现类,submit()用于Callable接口的实现类。常见实现类是ThreadPoolExecutor,如果要设置线程的属性如数量、生命周期,必须转化成实现类,可以采用强转的方式。
举例:thread\ThreadPoll.java
线程池的优点
相比其他三种方式的优点:
- 线程池中的线程可以重复使用,不用每次创建新的对象,节约了资源。
- 减少了创建新线程需要的时间,提高了响应速度。
- 方便管理线程,可以设置诸如线程数量、生命周期的属性。
线程池的种类
- newFixedThreadPool:返回一个固定线程数量的线程池。当一个新的任务提交时,如果由空闲线程就会立即执行
- newSingleThreadExecutor:返回只有一个线程的线程池,多余的任务会加入到任务队列,先入先出。
- newCachedThreadPool:返回的线程数量不固定,优先使用已创建的线程。如果任务的数量超过了线程的数量,就新建一个线
- newScheduledThreadPool:返回一个ScheduledExceutorService对象,线程数量可以指定
举例:
public class ThreadPoll {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
Executors.newCachedThreadPool();
ThreadPoolExecutor s1 = (ThreadPoolExecutor) service;
s1.setCorePoolSize(15);
service.execute(new Runthread());
service.submit(new CallThread());
service.shutdown();
}
}
class Runthread implements Runnable{
@Override
public void run() {
}
}
class CallThread implements Callable{
@Override
public Object call() throws Exception {
return null;
}
}
自定义线程池
ThreadFactory:一个接口,专门用来创建新线程。
ThreadPoolExecutor类:
- 功能:
新建线程池,在需要自定义线程池的时候,就用这个类来实现。 - 构造器
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
举例:
public void customThread(){
ExecutorService service = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return null;
}
})
{
//拓展线程池的方法
//在线程之前执行
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
}
//在销毁过程中执行
@Override
protected void terminated() {
super.terminated();
}
};
//submit和execute都是执行线程,参数是要执行的方法
service.submit(this::task);
//
service.execute(this::task);
service.shutdown();
}
void task(){
}