多线程:在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理“。
并发(Concurrent):同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。
并行(Parallel):当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。其实决定并行的因素不是CPU的数量,而是CPU的核心数量,比如一个CPU多个核也可以并行。
进程(Process):是正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说CPU(寄存器),IO,内存,网络资源等。同样一个程序,同一时刻被两次运行了,那么他们就是两个独立的进程。
线程(Thread):是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程与线程的区别:
- 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;进程是系统资源分配的单位,线程是系统调度的单位。
- 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线;
- 进程之间相互独立,进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。同时线程还有自己的栈和栈指针,程序计数器等寄存器。
- 调度和切换:线程上下文切换比进程上下文切换要快得多。
多线程优缺点
优点:
(1) 用户界面可以在进行其它工作的同时CPU一直处于活动状态,可以让程序运行速度更快。
(2)占用大量处理时间的任务可以定期将处理器时间让给其它任务,可以提高CPU利用率。
缺点:
(1)等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源 ,如打印机等。
(2)对线程进行管理要求额外的 CPU开销,线程的使用会给系统带来上下文切换的额外负担。
(3)线程的死锁。即对共享资源加锁实现同步的过程中可能会死锁
Thread:
package com.qyq.test.demo01;
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 1; i <=20 ; i++) {
// System.out.println("com.qyq.test.dome01:"+i);
//获取到当前线程的名字
String threadName = Thread.currentThread().getName();
System.out.println(threadName+": "+i);
}
}
}
Thread的测试类:
package com.qyq.test.demo01;
public class TestThread {
public static void main(String[] args) {
//new 线程
MyThread myThread = new MyThread();
//开启线程
myThread.start();
for (int i = 1; i <= 20; i++) {
System.out.println("mian线程"+i);
}
}
}
使用Thread写三个人同时卖票小案例(三个人各自卖各自的票)
package com.qyq.test.demo02;
// 三个人同时卖票(各自卖各自的)
public class TicketThread extends Thread {
private String name;
private int ticket =10;
public TicketThread(String name){
this.name=name;
}
// public TicketThread(String name) {
// super(name);
// }
@Override
public void run() {
// for (int i = 0; i < ticket; i++) {
// System.out.println( Thread.currentThread().getName()+"卖掉一张票剩余:"+i+"张");
// }
while (ticket>0){
try {
//设值休眠时间
sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
// System.out.println(Thread.currentThread().getName()+"卖掉一张票,剩余"+--ticket);
System.out.println(name+"卖掉一张票,剩余"+--ticket);
}
}
public static void main(String[] args) {
TicketThread ticketThread1 =new TicketThread("时军涛");
TicketThread ticketThread2 =new TicketThread("aaa");
ticketThread1.start();
ticketThread2.start();
}
}
Runnable 练习小案例 (俩人共卖10张票)
Runnable类:
package com.qyq.test.demo03;
public class RunnableTest {
public static void main(String[] args) {
Ticket ticket =new Ticket();
Thread thread1 = new Thread(ticket, "aaa");
Thread thread2 = new Thread(ticket, "bbb");
thread1.start();
thread2.start();
}
}
测试类:
package com.qyq.test.demo03;
public class Ticket implements Runnable{
//票数
private int ticket = 10;
@Override
public void run() {
while (ticket>0){
System.out.println(Thread.currentThread().getName()+"卖掉一张票,剩余:"+--ticket);
}
}
}
callable 练习:
callable有两种实现方法:
1.使用FutureTasshi
2.使用线程池
package com.qyq.test.demo05;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
//callable可以有返回值,也可以抛出异常的特性
public class CallableTest implements Callable {
@Override
public Object call() throws Exception {
//执行线程业务的方法
for (int i = 0; i < 10; i++) {
//返回正在执行的线程实例
System.out.println(Thread.currentThread().getName()+"执行打印"+i);
}
//获取随机数
UUID uuid = UUID.randomUUID();
System.out.println("随机数字字符串为:"+uuid);
return uuid;
}
public static void main(String[] args) {
//Callable的两种执行方式:
//1.
CallableTest callableTest = new CallableTest();
//使用FutureTask包装类
FutureTask futureTask = new FutureTask<>(callableTest);
//包装为Thread
Thread thread = new Thread(futureTask);
thread.start();
/**
//2.
CallableTest callableTest = new CallableTest();
//创建一个线程池
ExecutorService executorService = Executors.newCachedThreadPool();
Future future = executorService.submit(callableTest);
// 这个接口实现的线程,是有返回值的
*/
}
}
线程池练习:
ExecutorService executorService = Executors.newFixedThreadPool(设值线程最大并行数);
package com.qyq.test.demo06;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool implements Runnable{
@Override
public void run() {
for (int i = 0; i < 6; i++) {
System.out.println(Thread.currentThread().getName()+"执行打印"+i);
}
}
public static void main(String[] args) {
//实例化线程类
ThreadPool threadPool = new ThreadPool();
ThreadPool threadPool2 = new ThreadPool();
ThreadPool threadPool3 = new ThreadPool();
ThreadPool threadPool4 = new ThreadPool();
//使用Executors创建固定长度为4的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
//调用exectorService启动线程
executorService.execute(threadPool);
executorService.execute(threadPool2);
executorService.execute(threadPool3);
executorService.execute(threadPool4);
}
}
多线程匿名(Anonymous)内部类用法:
package com.qyq.test.demo07;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class AnonymityThread {
public static void main(String[] args) {
//继承Thread启用线程
new Thread(){
@Override
public void run() {
for (int i = 0; i < 3; i++) {
//返回正在执行的线程实力
//getName() 获取当前线程实例的名称
System.out.println(Thread.currentThread().getName()+"执行打印"+i);
}
}
}.start();
System.out.println("--------------------------");
//实现Runnable接口
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
//返回正在执行的线程实力
//getName() 获取当前线程实例的名称
System.out.println(Thread.currentThread().getName()+"执行打印"+i);
}
}
}).start();
System.out.println("--------------------------");
//实现callable接口
new Thread(new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
for (int i = 0; i < 3; i++) {
//返回正在执行的线程实力
//getName() 获取当前线程实例的名称
System.out.println(Thread.currentThread().getName()+"执行打印"+i);
}
return "callable可以抛异常可以返回值";
}
})).start();
}
}
线程优先级:“理论优先!!! ”
这是个玄学问题是真的理论优先!!!
package com.qyq.test.demo08;
public class PriorityThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+"执行线程"+i);
}
}
public static void main(String[] args) {
PriorityThread priorityThread = new PriorityThread();
Thread thread1 = new Thread(priorityThread, "a");
Thread thread2 = new Thread(priorityThread, "b");
Thread thread3 = new Thread(priorityThread, "c");
thread1.setPriority(10);
thread2.setPriority(5);
thread3.setPriority(1);
thread1.start();
thread2.start();
thread3.start();
}
}