中高阶架构师的必经之路:
高可用、高并发、高性能网站开发
多线程基本概念:
多个进程同时进
线程:调度和执行的单位(cpu的调度)
进程:作为资源分配的单位(操作系统的分配)
线程是进程的一部分
用户线程和守护线程
用户线程:java虚拟机所有用户线程dead后,程序就会结束
守护线程:辅助用户线程进行工作,不适用于I/O输入输出以及计算操作,避免程序结束后,任务不能执行完。
守护线程使用情景:
1、JVM垃圾回收
2、内存管理
3、数据库连接池监听状态等
多线程的实现
1、基础Thread类,实现run方法
实例1:
//多实现少继承:
//继承也许需要继承多个类而实现不需要考虑这些
public class test10 {
//创建线程:1、继承Thread+重写run
//2、创建子类对象+start
public static void main(String[] args){
}
}
class MyThread extends Thread{
public void run(){
for(int i = 0;i<20;i++){
System.out.println("听歌");
}
}
public static void main(String[] args){
//启动线程
MyThread my = new MyThread();
my.start();//两条线程同时运行,不会互相干扰
for(int i = 0;i<20;i++){
System.out.println("跳舞");//由cpu去调配
}
}
}
运行结果
继承Thread类,实现run方法,通过实例的start()方法,告知系统可以开始运行该run方法,根据系统调度器分配运行时间片,进行运行。
多次运行,运行结果不相同。
实现跳舞的线程和实现听歌的线程不相同。
实例2(多线程与I/O结合:多线程实现图片下载)
public class test11 {
public static void main(String[] args){
String url1 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540353806265&di=e4258c87892a1b4080891f0d03241a74&imgtype=0&src=http%3A%2F%2Fimg2.dwstatic.com%2Fnews%2F1809%2F401517849603%2F401517880783.jpeg";
String url2 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540948740&di=6ec8f3d51fdc501444cd58d47971db87&imgtype=jpg&er=1&src=http%3A%2F%2F07.imgmini.eastday.com%2Fmobile%2F20171102%2F20171102173205_2fb5db37f5a7fcb32d6054adcb21f28a_1.jpeg";
String url3 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540354085940&di=2aec582b87582ecb0426bede2462f987&imgtype=0&src=http%3A%2F%2Fpic.anzogame.com%2Flol%2Fnews%2F20140829%2F14092426723701_org.jpg";
MyThread2 dl1 = new MyThread2(url1,"E:/for_file/2.png" );
MyThread2 dl2 = new MyThread2(url2,"E:/for_file/3.png" );
MyThread2 dl3 = new MyThread2(url3,"E:/for_file/4.png" );
dl1.start();
dl2.start();
dl3.start();
}
}
class Downloadimg{
public void Download(String url, String path){
try {
FileUtils.copyURLToFile(new URL(url),new File(path) );
} catch (IOException e) {
e.printStackTrace();
}
}
}
class MyThread2 extends Thread{
private String url;
private String path;
public MyThread2(String url,String path){
this.url = url;
this.path = path;
}
public void run() {
Downloadimg dli = new Downloadimg();
dli.Download(this.url,this.path );
}
}
引用Commons IO jar包中的方法进行文件内容的复制,其实变相于下载。
实现runnable接口
class MyThread implements Runnable{
public void run(){
for(int i = 0;i<5;i++){
System.out.println("听歌");
}
}
public static void main(String[] args){
//创建实现类对象
MyThread my = new MyThread();
//创建代理类对象
Thread t = new Thread(my);
t.start();
for(int i = 0;i<5;i++){
System.out.println("跳舞");//由cpu去调配
}
}
}
实现接口,重写run方法,然后创建子类对象和Thread类的代理对象,通过将子类对象以传参的形式传给代理对象,通过调用代理对象的start()方式进行调度。
如果只运行一次,可以如上进行编码;
相比较继承类,推荐实现接口的方法:
1、方便共享资源
2、继承类单继承的局限性
Thread类的源码:
参数1:可运行目标
参数2:姓名(给线程赋予称号)
实例:
public class test10 {
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my,"小二").start();
new Thread(my,"小一").start();
}
}
class MyThread implements Runnable{
private int num = 20;
@Override
public void run() {
while(true){
if(num<0){
break;
}
System.out.println(Thread.currentThread().getName()+"----"+num--);
}
}
}
单任务多线程并给每个线程设定名字
运行结果
当一个任务有多个代理共同执行时,如果有网络延迟等问题,会导致并发,这时候就是线程不安全,需要进行处理。
实现Callable的Call方法
public class test10 {
public static void main(String[] args) {
//创建执行服务
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
ExecutorService es = Executors.newFixedThreadPool(2);
//提交执行
Future
Future
//获取结果
try {
String re1 = r1.get();
System.out.println(re1);
String re2 = r2.get();
System.out.println(re2);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//关闭服务
es.shutdownNow();
}
}
class MyThread implements Callable
@Override
public String call() throws Exception {
return "有些失望是不可避免的,但大部分的失望,都因为你高估了自己。";
}
}
运行结果
比较复杂,暂时只需要了解:
继承Callable接口,实现call方法,确定返回值类型。
执行操作:
1、创建执行服务 ExecutorService es = Executors.newFixedThreadPool(2);
2、提交任务 Future
3、接受返回值 String r = r1.get();
4、结束服务 es.shutdownNow();
java与I/O流详解
CommonsIO环境搭建
java多线程快速实现