多线程
1.Process和Thread
- 程序 是指指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念
- 进程 则是执行程序的一次执行过程,他是一个动态的概念,是系统资源分配的单位
- 通常在一个进程中可以包含若干个线程,一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位
- 注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器,如果是模拟出来的多线程,即在一个cpu 的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉
2.多线程的三种创建方法
(1)继承 Thread 类(重点)
//创建线程方法一步骤:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由cpu调度执行
public class TestThread02 extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 100; i++) {
System.out.println("学习线程--"+i);
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个线程对象
TestThread02 testThread = new TestThread02();
testThread.start();//开启线程
for (int i = 0; i < 1000; i++) {
System.out.println("努力学习多线程--"+i);
}
}
}
(2)实现 Runnable 接口(重点)
//创建线程方法二步骤:实现runnable接口,重写run方法,
//执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread01 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("学习多线程体---" + i);
}
}
public static void main(String[] args) throws InterruptedException {
//创建runnable接口的实现类对象
TestThread01 testThread01 = new TestThread01();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(testThread01);
thread.start();
// new Thread(new TestThread01()).start();
for (int i = 0; i < 100; i++) {
if(i%10==0) thread.sleep(20);
System.out.println("我在学习多线程--"+i);
}
}
}
(3)实现 Callable 接口(了解)
- 实现Callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:Future result1 = ser.submit(t1);
- 获取结果:boolean r1 = result1.get();
- 关闭服务:ser.shutdownNow();
3.静态代理
//静态代理模式总结:
//真实对象和代理对象都要实现同一个接口
//代理对象要代理真实角色
//好处:代理对象可以做很多真实对象做不了的事情
//真实对象专注做自己的事情
public class StaticProxy {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我爱你");
}
}).start();
new WeddingCompany(new You()).HappyMarry();
// You you = new You();//你要结婚
// WeddingCompany weddingCompany = new WeddingCompany(you);
// weddingCompany.HappyMarry();
}
}
//接口
interface Marry{
void HappyMarry();
}
//真实结婚角色
class You implements Marry{
//重写方法
@Override
public void HappyMarry() {
System.out.println("小红要结婚了");
}
}
//代理角色,帮助结婚
class WeddingCompany implements Marry{
private Marry target;//代理对象
public WeddingCompany(Marry target) {
this.target = target;//代理谁——》真实目标对象
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();//真实对象
after();
}
private void after() {
System.out.println("结婚之后,收尾款");
}
private void before() {
System.out.println("结婚之前,布置现场");
}
}
4.Lambda表达式
函数式接口的定义:任何接口,如果只包含唯一一个抽象方法,那么他就是一个函数式接口。
/*
总结:
lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行,那么就用代码块包裹
前提是接口为函数式接口
多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
interface ILove{
void love(int a,int b,int c);
public static void main(String[] args){
ILove love = null;
love = (a,b,c)->{
System,out.println("i love you" + a+b+c);
System.out.println("i love you too");
}
love.love(520,13,14);
}
*/
public class TestLambda01 {
//3.静态内部类
static class Like1 implements ILike{
@Override//重写方法
public void lambda() {
System.out.println("i like lambda02");
}
}
//主函数
public static void main(String[] args) {
//4.局部内部类
class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda03");
}
}
ILike like = new Like();
like.lambda();//类
like = new Like1();
like.lambda();//静态
like = new Like2();
like.lambda();//局部
//5.匿名内部类,没有类的名称,必须借助接口或者父类
like = new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda04");
}
};
like.lambda();//匿名
//6.用lambda简化
like = ()->{
System.out.println("i like lambda05");
};
like.lambda();//简化
}
}
//1.定义一个函数式接口
interface ILike{
void lambda();
}
//2.实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda01");
}
}
5.停止线程
//测试stop方法,
//建议线程正常停止,利用次数,不建议死循环
//建议使用标志位,不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{
private boolean flag = true;
@Override
public void run() {
int i = 0;
while(flag){
System.out.println("run....Thread"+i++);
}
}
public void stop(){
this.flag = false;
}
public static void main(String[] args) throws InterruptedException {
//启动线程
TestStop testStop = new TestStop();
Thread thread = new Thread(testStop);
thread.start();
//主线程
for (int i = 0; i < 500; i++) {
if(i==200){
testStop.stop();
System.out.println("线程该停止了");
}
}
}
}
6.线程休眠
sleep时间达到后线程进入就绪状态,可模拟网络延迟,倒计时
每个对象都有一个锁,sleep不会释放锁
//模拟倒计时...
public class TestSleep01 {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印当前系统时间
Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
while (true){
try {
Thread.sleep(1000);//每次输出间隔1s
// SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
// String dateString = simpleDateFormat.format(startTime);
// System.out.println(dateString);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void tenDown() throws InterruptedException {
int num = 10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0) break;
}
}
}
//模拟网络延迟:放大问题的发生性
public class TestSleep02 implements Runnable{
private int ticketNum = 10;
@Override
public void run() {
while (true){
if(ticketNum<=0) break;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNum--+"票");
}
}
public static void main(String[] args) {
TestSleep02 ticket = new TestSleep02();
new Thread(ticket,"小明").start();
new Thread(ticket,"抢票的人").start();
new Thread(ticket,"黄牛").start();
}
}
7.线程礼让 Yield
//测试礼让线程,让当前执行的线程暂停,但不阻塞
//礼让不一定成功,看cpu心情
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();//礼让
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
8.Join合并线程
//测试join方法,想象为插队:待此线程执行完成后,再执行其他线程,其他线程阻塞
public class TestJoin implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("vip线程来了"+i);
}
}
public static void main(String[] args) throws InterruptedException {
//启动线程
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主线程
for (int i = 0; i < 500; i++) {
if(i==200){
thread.join();//插队
}
System.out.println("main"+i);
}
}
}
9.线程优先级
线程的优先级用数字表示1~10,表示概率,还是要看CPU的调度
public class TestPriority {
public static void main(String[] args) {
//主线程默认优先级
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
//先设置优先级,再启动
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(7);
t5.start();
t6.setPriority(2);
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
10.守护线程 daemon
//测试守护线程
//例子:上帝守护人
public class TestDaemon {
public static void main(String[] args) throws InterruptedException {
God god = new God();
Person person = new Person();
Thread t2 = new Thread(person);
Thread thread = new Thread(god);
thread.setDaemon(true);//默认为false表示用户线程,正常的线程都是用户线程
thread.start();//上帝守护线程启动
new Thread(person).start();//用户线程启动
}
}
//上帝
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("上帝保佑着你");
}
}
}
//人
class Person implements Runnable{
@Override
public void run() {
for (int i = 0; i < 3600; i++) {
System.out.println("人开心的活着");
}
System.out.println("=====goodBye===========");
}
}
11.线程状态
//观察测试线程的状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("//");
});
//观察状态
Thread.State state = thread.getState();
System.out.println(state);//NEW
//观察线程后
thread.start();//启动线程
state = thread.getState();//节约空间
System.out.println(state);//Run
while(state != Thread.State.TERMINATED){//只要线程不终止,就一直输出状态
Thread.sleep(100);
state = thread.getState();//更新线程状态
System.out.println(state);//输出状态
}
}
}
12.线程同步
锁机制 synchronized,当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可
synchronized关键字包括两种方法:
synchronized方法 public synchronized void method(int args){ }
synchronized块 synchronized(Obj){ }
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"酷酷的小明").start();
new Thread(station,"牛牛").start();
new Thread(station,"可恶的黄牛").start();
}
}
class BuyTicket implements Runnable{
private int ticketNum = 10;
boolean flag = true;//外部停止方法
@Override
public void run() {
//买票
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private synchronized void buy() throws InterruptedException {
//判断是否有票
if(ticketNum<=0){
flag = false;
return;
}
//模拟延时
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"拿到"+ticketNum--);
}
}
public class UnsafeList {
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
synchronized (list){//同步块
list.add(Thread.currentThread().getName());
}
}).start();
}
Thread.sleep(3000);
System.out.println((list.size()));
}
}
13.使用线程池
JDK5.0起提供了线程池相关API: ExecutorService和Executors(工具类,线程池的工厂类)
public class TestPool {
public static void main(String[] args) {
//1.创建服务,创建线程池
//newFixedThreadPool 参数为:线程池的大小
ExecutorService service = Executors.newFixedThreadPool(10);
//执行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//关闭连接池
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}