线程基础知识java

一、线程

1、简介
在这里插入图片描述
多线程:是指从软硬件上实现多条执行流程的技术。
例子:多用户登录、百度网盘同时上传和下载文件。
在这里插入图片描述
2、多线程的创建
主要有三种方式:分别是继承线程类,实现Runnable接口(可以用匿名类实现),实现Callable接口.
在这里插入图片描述
缺点方面因为只能继承一个类,不利于功能扩展。

public class ThreadDemo1 {
	public static void main(String[] args) {
		//3、new一个线程对象
		Thread t = new MyThread();
		//4、调用start方法启动线程(执行的还是run方法)
		t.start();
		
		for(int i=0;i<5;i++) {
			System.out.println("主线程执行输出"+i);
		}
	}
}

/**
 * 1、定义一个线程类继承Thread类
 */
class MyThread extends Thread{
	/**
	 * 2、重写run方法,里面是定义线程以后要干啥
	 */
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println("子线程执行输出"+i);
		}
	}
}

在这里插入图片描述
所以需要将子线程放到主线程前,这样才会有多线程。

在这里插入图片描述
在这里插入图片描述
缺点上即只能跑功能不能返回执行结果,因为是void run()

public class ThreadDemo2 {
	public static void main(String[] args) {
		//3、创建一个任务对象
		Runnable target=new MyRunnable();
		//4、把任务对象交给Thread处理(把任务对象交给线程对象处理)
		Thread t=new Thread(target);
		//5、启动线程
		t.start();
		
		for(int i=0;i<10;i++) {
			System.out.println("主线程执行输出"+i);
		}
	}
}

/**
 * 1、定义一个线程任务类,实现Runnable接口
 */
class MyRunnable implements Runnable{
	/**
	 * 2、重写run方法,定义线程的执行任务
	 */
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<5;i++) {
			System.out.println("子线程执行输出"+i);
		}
	}
}
public class ThreadDemo2Other {
	public static void main(String[] args) {
		Runnable target=new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<10;i++) {
					System.out.println("子线程1执行输出"+i);
				}
			}
		};
		Thread t=new Thread(target);
		t.start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<10;i++) {
					System.out.println("子线程2执行输出"+i);
				}
			}
		}).start();
		
		new Thread(()-> {
				for(int i=0;i<10;i++) {
					System.out.println("子线程3执行输出"+i);
				}
		}).start();
		
		for(int i=0;i<10;i++) {
			System.out.println("主线程执行输出"+i);
		}
	}
}

在这里插入图片描述
在这里插入图片描述

public class ThreadDemo3 {
	public static void main(String[] args) {
		//3、创建任务对象
		Callable<String> call1=new MyCallable(100);
		//4、把Callable任务对象交给FutureTask对象
		//FutureTask对象的作用1:是Runnable的对象(实现了Runnable接口),可以交给Thread
		//FutureTask对象的作用2:可以在线程执行完毕后通过调用其get方法得到线程执行完成的结果
		FutureTask<String> f1=new FutureTask<>(call1);
		//5、交给线程处理
		Thread t1=new Thread(f1);
		//6.启动线程
		t1.start();
		
		Callable<String> call2=new MyCallable(200);
		FutureTask<String> f2=new FutureTask<>(call2);
		Thread t2=new Thread(f2);
		t2.start();
		
		try {
		   //如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果
			String rs1=f1.get();
			System.out.println("第一个结果"+rs1);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			//如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果
			String rs2=f2.get();
			System.out.println("第二个结果"+rs2);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}

/**
 *1、定义一个任务类,实现Callable接口 ,应该声明线程任务执行完毕后的结果的数据类型
 */
class MyCallable implements Callable<String>{
	
	private int n;
	public MyCallable(int n) {
		this.n=n;
	}
	/**
	 * 2、重写call方法(任务方法)
	 */
	@Override
	public String call() throws Exception {
		int sum=0;
		for(int i = 1; i <= n; i++) {
			sum += i;
		}
		return "子线程执行结果:"+sum;
	}
}

在这里插入图片描述
在这里插入图片描述
3、Thread的常用方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class MyThread extends Thread {
	public MyThread() {
		
	}
	public MyThread(String name) {
		//为当前线程对象设置名称,送给父类的有参数构造器
		super(name);
	}
	
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(Thread.currentThread().getName()+"线程输出:"+i);
		}
	}
}
public class ThreadDemo1 {
	//main方法是由主线程负责调度的
	public static void main(String[] args) {
		Thread t1=new MyThread("1号");
		//t1.setName("1号");
		t1.start();
		System.out.println(t1.getName());
		
		Thread t2=new MyThread("2号");
		//t2.setName("2号");
		t2.start();
		System.out.println(t2.getName());
		
		//哪个线程执行它,它就得到哪个线程对象
		//主线程名称就叫main
		Thread m=Thread.currentThread();
		System.out.println(m.getName());
		m.setName("最牛线程");
		for (int i = 0; i < 5; i++) {
			System.out.println(m.getName()+"线程输出:"+i);
		}
	}
}

public class ThreadDemo2 {
	public static void main(String[] args) throws Exception {
		for(int i=1;i<=5;i++) {
			System.out.println("输出:"+i);
			if(i==3) {
				//让线程进入休眠状态
				Thread.sleep(3000);
			}
		}
	}
}

在这里插入图片描述
4、线程安全
线程安全问题:多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题。
在这里插入图片描述
在这里插入图片描述

public class Account {
	private String cardId;
	private double money;//账户余额
	
	public Account() {
		
	}
	public Account(String cardId,double money) {
		this.cardId=cardId;
		this.money=money;
	}
	
	public void drawMoney(double money) {
		//0.先获取是谁来取钱
		String name=Thread.currentThread().getName();
		//1、判断账户是否共享
		//同步代码块
		//this==acc共享账户
		synchronized (this) {
			if(this.money>=money) {
				//2、取钱
				System.out.println(name+"来取钱:"+money);
				//3、更新余额
				this.money-=money;
				System.out.println(name+"取钱后剩余:"+this.money);
			}else {
				//4、余额不足
				System.out.println(name+"取钱余额不足");
			}
		}
	}
	
	public String getCardId() {
		return cardId;
	}
	public void setCardId(String cardId) {
		this.cardId = cardId;
	}
	public double getMoney() {
		return money;
	}
	public void setMoney(double money) {
		this.money = money;
	}
	public static void run() {
		synchronized (Account.class) {//静态方法中同步代码块的锁对象形式
		}
	}
	
}

/**
 取钱的线程类
 */
public class DrawThread extends Thread{
	private Account acc;
	public DrawThread(Account acc,String name) {
		super(name);
		this.acc=acc;
	}
	@Override
	public void run() {
		//取钱的
		acc.drawMoney(100000);
	}
}
public class ThreadDemo {
	public static void main(String[] args) {
		//1、定义线程类,创建一个共享的账户对象
		Account acc=new Account("ICBC-111",100000);
		
		//2、创建2个线程对象,代表小明和小红同时进来了
		new DrawThread(acc,"小明").start();
		new DrawThread(acc,"小红").start();
		
	}
}

5、线程同步
为了解决线程安全问题。
取钱案例出现问题的原因:多个线程同时执行,发现账户都是够钱的。
如何才能保证线程安全:让多个线程实现先后依次访问共享资源。
线程同步的核心思想: 加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

1)方法
同步代码块
在这里插入图片描述
同步方法
在这里插入图片描述
在这里插入图片描述
同步代码块锁的范围更小,同步方法锁的范围更大
在这里插入图片描述
lock锁
在这里插入图片描述

private final Lock lock=new ReentrantLock();
public void drawMoney(double money) {
		//0.先获取是谁来取钱
		String name=Thread.currentThread().getName();
		//1、判断账户是否共享
		lock.lock(); //上锁
		try {
			if(this.money>=money) {
				//2、取钱
				System.out.println(name+"来取钱:"+money);
				//3、更新余额
				this.money-=money;
				System.out.println(name+"取钱后剩余:"+this.money);
			}else {
				//4、余额不足
				System.out.println(name+"取钱余额不足");
			}
		}finally {
			lock.unlock();//解锁,用try...finally保证一定能解锁
		}
			
	}

6、线程通信
在这里插入图片描述
线程通信的前提:线程通信通常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全。
在这里插入图片描述

7、线程池【重点】
1)线程池概述
在这里插入图片描述
在这里插入图片描述
可以看作服务员服务客人的模式。

2)线程池实现的API、参数说明
在这里插入图片描述
在这里插入图片描述
其中线程池中的非核心线程可以看作是临时工,核心线程是正式工,不会消失。
在这里插入图片描述
3)线程池处理Runnable任务
在这里插入图片描述
在这里插入图片描述

public class MyRunnable implements Runnable {
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(Thread.currentThread().getName()+"输出:Helloword"+i);
		}
		try {
			System.out.println(Thread.currentThread().getName()+"本任务与线程绑定,线程进入休眠了!");
			Thread.sleep(1000000);  //即占用该线程
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}
/**
 目标:自定义一个线程池对象,并测试其特性
 */
public class ThreadPoolDemo1 {

	public static void main(String[] args) {
		// 1、创建线程池对象
		ExecutorService pool=new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
		
		//2、给任务线程池处理
		Runnable target=new MyRunnable();
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		//创建临时线程(因为核心线程和任务队列都满了才创建临时线程)
		pool.execute(target);
		pool.execute(target);
		//不创建,拒绝策略被触发
		pool.execute(target);
		
		//关闭线程池(开发中一般不会使用)
		pool.shutdownNow();//立即关闭,即使任务没有完成
		//pool.shutdown();//会等待任务完成后关闭

	}

}

4)线程池处理Callable任务
在这里插入图片描述
FutureTask是Future(父类)的实现类对象

public class MyCallable implements Callable<String>{
	private int n;
	public MyCallable(int n) {
		this.n=n;
	}
	@Override
	public String call() throws Exception {
		int sum=0;
		for(int i=1;i<=n;i++) {
			sum+=i;
		}
		return Thread.currentThread().getName()+"执行结果:"+sum;
	}
}

public class ThreadPoolDemo2 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 1、创建线程池对象
		ExecutorService pool=new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
		
		//2、给任务线程池处理
		Future<String> f1= pool.submit(new MyCallable(100));
		Future<String> f2= pool.submit(new MyCallable(200));
		Future<String> f3= pool.submit(new MyCallable(300));
		Future<String> f4= pool.submit(new MyCallable(400));
		Future<String> f5= pool.submit(new MyCallable(500));
		
		//String rs=f1.get();
		System.out.println(f1.get());
		System.out.println(f2.get());
		System.out.println(f3.get());
		System.out.println(f4.get());
		System.out.println(f5.get());

	}

}

5)Executors工具类实现线程池
在这里插入图片描述

public class ThreadPoolDemo3 {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 1、创建固定线程数据的线程池
		ExecutorService pool=Executors.newFixedThreadPool(3);
		
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());//已经没有多余的线程了
		
		

	}

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
8、定时器
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public class TimerDemo2 {
	public static void main(String[] args) {
		//1、创建ScheduledExecutorService线程池,做定时器
		ScheduledExecutorService pool=Executors.newScheduledThreadPool(3);
		
		//2、开启定时任务
		pool.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println(Thread.currentThread().getName()+"执行输出aaa"+new Date());
				try {
					Thread.sleep(10000);
				} catch (Exception e) {
					// TODO: handle exception
				}
			}
		}, 0, 2, TimeUnit.SECONDS);
		
		pool.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println(Thread.currentThread().getName()+"执行输出bbb"+new Date());
			}
		}, 0, 2, TimeUnit.SECONDS);
	}
}

9、并发、并行
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
10、线程的生命周期
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值