02 创建线程
创建线程有如下三种方式:
-
继承Thread类(因为是继承,所以继承了Thread就不能继承其他类)
-
实现Runnable接口(重点,接口可以有多实现,所以推荐使用,Thread类也是实现了RUnnable接口的)
-
实现Callable接口(有返回消息)
继承Thread类
package cn.deexin.thread;
//继承Thread类
public class MyThread1 extends Thread{
//重写run方法
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("Hello,world"+i);
}
}
//主线程
public static void main(String[] args) {
//new一个我们的线程
MyThread1 myThread1=new MyThread1();
//线程开始执行
myThread1.start();
//调用run方法,没有开启线程,只是按照普通方法执行!!!
myThread1.run();
for (int i = 0; i < 20; i++) {
System.out.println("主线程"+i);
}
}
}
线程开启不一定立即执行,由cpu调度。
实现Runnable接口
package cn.deexin.runnable;
//实现runnable接口
public class MyRunnable implements Runnable {
//重写run方法
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("hello,world"+i);
}
}
//主线程
public static void main(String[] args) {
//创建runnable接口实现类对象
MyRunnable myRunnable=new MyRunnable();
//创建代理类线程对象,通过线程对象来k开启我们的线程,
Thread thread=new Thread(myRunnable);
//启动线程
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程"+i);
}
}
}
实现Callable接口
//Callable的好处
//1.可以定义返回值
//2.可以抛出异常
public class MyCallable implements Callable<Boolean> {
private String url;
private String name;
public MyCallable(String url,String name){
this.url=url;
this.name=name;
}
@Override
public Boolean call() throws Exception {
WebDownloader webDownloader=new WebDownloader();
webDownloader.download(url,name);
System.out.println("下载的图片名为"+name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable downloadImage1=new MyCallable("https://pics7.baidu.com/feed/b3b7d0a20cf431add37337b74c3fbea52fdd98a9.jpeg?token=90af8878c0cf90b13ac859cde8b873ea","1.jpg");
MyCallable downloadImage2=new MyCallable("https://t12.baidu.com/it/u=2813575936,168938841&fm=30&app=106&f=JPEG?w=312&h=208&s=477A7BCAEB3BB2C62E7CB41C030050D2","2.jpg");
MyCallable downloadImage3=new MyCallable("https://t11.baidu.com/it/u=2351765601,168930212&fm=30&app=106&f=JPEG?w=312&h=208&s=9A027A2159E933035B1C3983010060B1","3.jpg");
//创建执行服务
ExecutorService ser= Executors.newFixedThreadPool(2);
//提交执行
Future<Boolean> result1= ser.submit(downloadImage1);
Future<Boolean> result2= ser.submit(downloadImage2);
Future<Boolean> result3= ser.submit(downloadImage3);
//获取结果
Boolean b1=result1.get();
Boolean b2=result2.get();
Boolean b3=result3.get();
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
//关闭服务
ser.shutdownNow();
}
}
//下载器
class WebDownloader{
//下载方法
public void download(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常,downloader方法出现问题!");
}
}
}
火车票列子
//多个线程操作同一个对象
//买火车票的列子
public class HuoChePiao implements Runnable {
//票数
private int ticketNums = 10;
@Override
public void run() {
while (true) {
if (ticketNums <= 0) {
break;
}
//模拟延时
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "拿到了火车票" + ticketNums--);
}
}
public static void main(String[] args) {
HuoChePiao xiaoming = new HuoChePiao();
new Thread(xiaoming,"小红").start();
new Thread(xiaoming,"小明").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
new Thread(xiaoming,"黄牛党").start();
}
}
执行结果:
从执行结果来看,我们发现了一问题 由多个人拿到了火车票10 ,还有拿到了火车票-1的 这说明:多个线程操作同一个资源的情况下,会造成线程不安全,线程紊乱的问题,那么怎么去解决呢?