线程与线程池
进程是什么?
进程:正在运行的程序,进程是CPU分配的最小单元
线程是什么?
线程:线程是进程中的一个执行单元,线程是CPU调度的最小单元
一个进程中至少有一个线程,也就是主线程(mainThread),也可以
添加其他子程序!线程之间各自执行,互不干扰!
多线程开发:就是在程序中创建多条线程开发程序!
线程与死锁
两种创建子线程的方式:
-
Thread类
a.创建类并且继承于Thread
b.重写run方法
c.把需要放在子线程中操作的代码放在run方法中
d.创建对象,调用start方法 -
Runable 接口
a.创建类并且实现Runable接口
b.重写run方法
c.把需要放在子线程中操作的代码放在run方法中
d.创建Thread对象,把之前创建的类作为Thread构造方法的参数
e.Thread对象 调用start方法
方式一
创建类并继承Thread
package com.thread;
public class MyThread extends Thread {
public void run() {
//注意注意!!需要放在子线程中实现的方法 请写这里
System.out.println(Thread.currentThread().getName());
System.out.println("这是MyThread");
}
}
创建对象,调用start方法
package com.thread;
public class ThreadTest {
public static void main(String[] args) {
// int a=10;
// System.out.println(Thread.currentThread().getName());//获得线程的名字
//方式1
MyThread myThread=new MyThread();
// myThread.run(); main主线程执行
myThread.start();//子线程执行
}
}
方式二
创建类并且实现Runable接口
package com.thread;
public class MyRunable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
System.out.println("这里是MyRunable");
}
}
创建对象,调用start方法
package com.thread;
public class ThreadTest {
public static void main(String[] args) {
//方式2
MyRunable myRunable=new MyRunable();
Thread thread=new Thread(myRunable);
thread.start();
}
}
方式三
匿名内部类的写法 缺点:只会走一次啦
package com.thread;
public class ThreadTest {
public static void main(String[] args) {
Thread thread2=new Thread() {
@Override
public void run() {
System.out.println("这是第三(1)种写法"+Thread.currentThread().getName());
}
};
thread2.start();
//===========
new Thread() {
@Override
public void run() {
System.out.println("这是第三(2)种写法"+Thread.currentThread().getName());
}
}.start();
}
}
方式四
Runable的匿名类写法
package com.thread;
public class ThreadTest {
public static void main(String[] args) {
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("这是Runnable的匿名类"+Thread.currentThread().getName());
}
};
Thread thread3=new Thread(runnable);
thread3.start();
}
}
练习:做一个卖票的练习
分析:来个人买票,这张票其他人就不能再买了,不然容易一张票被几个人买。所以要加一个锁,死锁就是一个线程进入其他的线程进不去
创建类并且实现Runable接口中的run方法
package com.thread;
import java.util.concurrent.locks.ReentrantLock;
public class SaleTicket implements Runnable{
//定义总票数
int count =100;
private ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
String name=Thread.currentThread().getName();
while(true) {
//lock() 加锁
lock.lock();
try {
Thread.sleep(500);
if(count>0) {
count--;
System.out.println(name+"在卖第"+(100-count)+"票");
}else {
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
}
测试:
package com.thread;
public class ThreadTest {
public static void main(String[] args) {
SaleTicket saleTicket=new SaleTicket();
Thread t1=new Thread(saleTicket,"窗口1");
Thread t2=new Thread(saleTicket,"窗口2");
Thread t3=new Thread(saleTicket,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
线程池
适用场景:单个任务时间短,但数量庞大
线程池:对线程的管理,合理的使用
特点:只管往线程池里添加任务即可,线程池会按照自身特点分配线程
一.缓存线程池
缓存线程池:无限大,当执行后面任务的时候,如果前面的任务
已经执行完毕,线程是可以复用,不是每个任务都会对应的创建线程。
package com.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService cachedThreadPool=Executors.newCachedThreadPool();
for (int i = 0; i < 30; i++) {
final int index=i;
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
//需要放在子线程中执行的代码
System.out.println(index);
System.out.println(Thread.currentThread().getName());
}
});
}
//关闭线程池
cachedThreadPool.shutdown();
}
}
二.固定线程池
固定线程池:线程池能够容纳的线程数量固定
package com.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService fixedThreadPool=Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index=i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(index);
System.out.println(Thread.currentThread().getName());
}
});
}
//关闭线程池
fixedThreadPool.shutdown();
}
}
三.单一线程池
单一线程池:只有一个线程 保证FIFO(先进先出)
package com.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService singleThreadExecutor=Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index=i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(index);
System.out.println(Thread.currentThread().getName());
}
});
}
//关闭线程池
singleThreadExecutor.shutdown();
}
}
四.定时线程池
定时线程池:支持定时已及周期性执行
方法一
package com.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(5);
//延时3秒 再执行任务
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("你迟到了3秒!罚你300个俯卧撑!");
}
}, 3, TimeUnit.SECONDS);//3+i
//第二个参数是延迟时间
//第三个参数是时间单元(就是时 分 秒 )
}
}
第二个方法
package com.pool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(5);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("呵呵");
}
}, 1, 3, TimeUnit.SECONDS);
//参数二是初次任务的延时时间
//参数3:是从第二次开始周期循环执行的间隔时间
}
}
OK!线程与线程池就这么多了;有点蒙,还好以后开发中用到线程的地方,别人都写好了以后会了在来看看吧!