多线程
创建线程的方式
方式一:
继承Thread类,重写run()方法
方式二
实现Runnable接口,重写run()方法
方式三
实现callable接口,重写call()方法
继承Thread类
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
例子:
/**
* 创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
*
* 总结:注意,线程开启不一定立即执行,有cup调度
* @author shkstart
* @create 2021-05-04 20:53
*/
public class TestThread1 extends Thread {
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在打代码。。。"+i);
}
}
public static void main(String[] args) {
// main线程,主线程
// 创建一个线程对象
TestThread1 testThread1 = new TestThread1();
// 调用start()方法开启线程
testThread1.start();
for (int i = 0; i < 200; i++) {
System.out.println("我也在打代码"+i);
}
}
}
练习:实现多线程同步下载图片
/**
* 练习Thread,实现多线程同步下载图片
* @author shkstart
* @create 2021-05-04 21:04
*/
public class TestThread2 implements Runnable {
private String url; // 网络图片地址
private String name; // 保存的文件名
public TestThread2(String url,String name){
this.url = url;
this.name = name;
}
// 下载图片线程的执行体
@Override
public void run() {
WebDwnloader webDwnloader = new WebDwnloader();
webDwnloader.downloader(url,name);
System.out.println("下载了文件名为"+name);
}
public static void main(String[] args) {
TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20210120054229.jpg","1.jpg");
TestThread2 t2 = new TestThread2("https://img-home.csdnimg.cn/images/20210120054229.jpg","2.jpg");
TestThread2 t3 = new TestThread2("https://img-home.csdnimg.cn/images/20210120054229.jpg","3.jpg");
// 理想状态下 t1->t2->t3 其实不是
t1.start();
t2.start();
t3.start();
}
}
// 下载器
class WebDwnloader{
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异常,下载方法出现问题");
}
}
}
实现Runnable接口
定义MyRunnable类实现Runnable接口
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
例子
/**
* 创建线程方式2:实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
* @author shkstart
* @create 2021-05-04 21:41
*/
public class TestThread3 implements Runnable {
@Override
public void run() {
// run方法线程体
for (int i = 0; i < 200; 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 < 200; i++) {
System.out.println("我也在打代码"+i);
}
}
}
练习:买火车票的例子
多个线程同时操作同一个对象
/**
* 多个线程同时操作同一个对象
* 买火车票的例子
*
*
* 发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
* @author shkstart
* @create 2021-05-04 21:41
*/
public class TestThread4 implements Runnable {
// 票数
private int ticketNums = 10;
@Override
public void run() {
while (true){
if (ticketNums <= 0){
break;
}
// 模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ ticketNums-- + "票");
}
}
public static void main(String[] args) {
TestThread4 testThread4 = new TestThread4();
new Thread(testThread4,"小明").start();
new Thread(testThread4,"老师").start();
new Thread(testThread4,"黄牛").start();
}
}
创建callable接口
callable的好处
1.可以定义返回值
2.可以抛出异常
例子
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println(name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable("https://img-home.csdnimg.cn/images/20210120054229.jpg","1.jpg");
TestCallable t2 = new TestCallable("https://img-home.csdnimg.cn/images/20210120054229.jpg","2.jpg");
TestCallable t3 = new TestCallable("https://img-home.csdnimg.cn/images/20210120054229.jpg","3.jpg");
// t1.start();
// t2.start();
// t3.start();
// 创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
// 提交执行
Future<Boolean> r1 = ser.submit(t1);
Future<Boolean> r2 = ser.submit(t2);
Future<Boolean> r3 = ser.submit(t3);
// 获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
// 关闭服务
ser.shutdownNow();
}
}
// 下载器
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
}
发现问题
多个操作同一个资源的情况下,线程不安全,数据紊乱