Java多线程
线程简介
多任务
通过多条道路解决多项任务:多人游戏,生活琐事,编程
多条执行路径,主线程和子线程并行交替执行
程序、进程、线程
一个进程可以有多个线程,如视频中同时听声音、图像、弹幕等
Process与Thread
- 程序:是指令和数据的有序集合,其本身并没有任何运行的含义,是一个静态的概念
- 进程:执行程序的一次执行过程,动态概念,是系统资源分配的单位
- 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程否则无意义;线程是CPU调度和执行的单位
PS:多线程大多为模拟,真实的多线程是指有多个CPU即多核,如服务器;如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码因为切换很快所以有同时执行的错觉
###核心概念
-
main( ),称之为主线程,为系统入口用于执行整个程序
-
一个进程中如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
-
对同一份资源进行操作时,会存在资源争抢问题,需要加入并发控制
-
线程会带来额外开销,如CPU调度时间,并发控制开销
-
每个线程在自己的工作内存交互,内存控制不当会导致数据不一致
线程的创建
三种创建方式:
- Thread class:继承Thread节点类(重点)
- Runnable接口:实现Runnable接口(重点)
- Callable接口:实现Callable接口
Thread
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启用线程
//创建线程方式一:继承Thread类,重写run方法,调用start方法开启线程
public class TestThread1 extends Thread{
@Override
public void run(){
//run方法线程体
for (int i = 1;i <= 20;i++){
System.out.println("看代码" + i);
}
}
public static void main(String[] args) {
//main方法主线程
//创建一个线程对象
TestThread1 testThread1 = new TestThread1();
//调用start方法开启线程
testThread1.start();
for (int i = 1; i <= 100; i++) {
System.out.println("学习多线程" + i);
}
}
}
/*
线程开启不一定立即执行,由CPU调度
*/
####网图下载
使用common-io.2.11.jar包
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
//联系Thread,实现多线程同步实现下载图片
public class TestThread2 extends Thread{//2.为实现线程类,继承Thread类变为线程类
private String url;//网络图片地址
private String name;//保存的文件名
public TestThread2(String url,String name){
this.url = url;
this.name = name;
}
//3.用构造器丢入url和name,重写了线程的执行体即run方法,
@Override
public void run(){
WebDownloader webDownloader = new WebDownloader();//4.调用方法
webDownloader.downloader(url,name);
System.out.println("下载了文件名为" + name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://p.qlogo.cn/hy_personal/3e28f14aa051684242c6be604248ad5e170822050ec983c3efd7f27026a2f2eb/0.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://wkphoto.cdn.bcebos.com/50da81cb39dbb6fdf6c3f7401924ab18972b373f.jpg","2.jpg");
TestThread2 t3 = new TestThread2("https://wkphoto.cdn.bcebos.com/a8014c086e061d95e31f255e6bf40ad162d9ca7f.jpg","3.jpg");
t1.start();//5.同时启动下载图片
t2.start();
t3.start();
//下载顺序为3、2、1,与代码顺序不符,表明是CPU同时执行实际为随机调度
}
}
//1.编写下载器,通过FileUtils工具类中的copyURLToFile方法,将一个网页地址变成一个文件以保存图片
class WebDownloader{
//下载方法
public void downloader(String url,String name){//编写下载方法
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
}
catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题");
}
}
}
Runnable
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程执行体
- 创建线程对象;传入目标对象+Thread对象.start()方法启动线程
//创建线程方式2:实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口实现类,调用start方法
public class TestThread3 implements Runnable{
@Override
public void run(){
//run方法实现线程体
for (int i = 0; i < 20; i++) {
System.out.println("看代码" + i);
}
}
public static void main(String[] args) {
//创建一个Runnable接口的实现对象
TestThread3 testThread3 = new TestThread3();
//创建线程对象,通过线程对象来开启线程
// Thread thread = new Thread(testThread3);
// thread.start();
new Thread(testThread3).start();
for (int i = 0; i < 20; i++) {
System.out.println("学习多线程" + i);
}
}
}
//多线程同时操作同一个对象
//买火车票
public class TestThread4 implements Runnable{
//票数
private int ticketNums = 10;
private Object object = new Object(); //声明一个对象为锁
//多个线程同时操作时,线程数据可能出现紊乱,如重复购票和突破限制
@Override
public void run(){
while (true){
synchronized(object) { //互斥操作,防止并发问题
if (ticketNums <= 0) {
break;
}
//模拟延时
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " get tickets NO." + ticketNums--);
//currentThread()该方法可获得线程本身,获得当前执行线程的名称
}
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"李华").start();
new Thread(ticket,"坤坤").start();
}
}
//模拟龟兔赛跑
public class Race implements Runnable{
private static String winner;
@Override
public void run(){
for (int i = 0; i <= 100; i++) {
//模拟兔子休息
if(Thread.currentThread().getName().equals("rabbit") && i%10==0){
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
boolean flag = gameover(i);
if(flag){
break;
}
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
}
}
//判断是否完成比赛
private boolean gameover(int steps){
if (winner != null){
return true;
}
{
if (steps == 100){
winner = Thread.currentThread().getName();
System.out.println("The winner is " + winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"rabbit").start();
new Thread(race,"turtle").start();
}
}