1、进程与线程
(1)进程:同一时间段只允许一个程序运行 。多进程允许同一时间段多个程序运行,但是同一时间点只能执行一个。
(2)线程:在进程之上划分的更小单元。线程依赖于进程支持,没有进程,线程不存在。线程启动速度远快于进程,并发处理时性能远高于进程。
2、实现多线程
(1)继承Thread类实现多线程
package xiancheng;
public class MyThread extends Thread{
@Override
public void run(){
//多线程执行的功能都需要在run方法中定义
//但是不能直接调用,启动多线程需要start()方法
for(int i= 0;i<10;i++){
System.out.println(i);
}
}
public static void main(String args[]) {
new MyThread().start();
new MyThread().start();
}
}
- 多线程执行的功能都需要在run方法中定义;
- 但是不能直接调用,启动多线程需要start()方法;
- 多教程交替执行,执行顺序不可控,虽然调用start方法,但是执行仍是run方法;
每一个线程只允许启动一次,否则会抛出异常;如下:
MyThread myThread = new MyThread() ;
myThread .start();
myThread .start();
(2)实现Runnable接口
该方式没有提供start启动方法,需要通过Thread 类启动(优先考虑)。
class xc implements Runnable{
@Override
public void run(){
//多线程执行的功能都需要在run方法中定义
//但是不能直接调用,启动多线程需要start()方法
for(int i= 0;i<10;i++){
System.out.println(i);
}
}
}
public class MyThread {
public static void main(String args[]) {
Thread thread = new Thread(new xc());
thread.start();
}
}
(3)实现Callable接口
Runnable接口无法获取返回值,Callable可以设置一个泛型,泛型类型为返回数据类型;
class xc implements Callable<String>{
@Override
public String call() throws Exception {
for(int x = 0; x<10; x++) {
System.out.print(x);
}
return "执行完毕";
}
}
public class MyThread {
public static void main(String args[]) throws InterruptedException, ExecutionException {
FutureTask<String> task = new FutureTask(new xc());
new Thread(task).start();
System.out.print(task.get());
}
}
对比:
- Thread继承,比较难以扩散,Runnable实现容易扩充;
- Thread类实现了Runnable接口;
- Thraed类提供了start、run方法,Runnable只提供run方法;
- Runnable需要通过Thread 类启动;
- Callable提供call方法,有返回值;
启动线程用Thread类的start方法;
3、线程运行状态
- 创建——》启动:任何线程启动都需要Thread类的start()方法,但是启动之后并未执行,只是进入就绪状态;
- 就绪——》执行:执行run方法之后从就绪到达执行状态,但是可能需要让出资源,进入阻塞状态,阻塞解除重新进入就绪状态;
- 执行——》停止:如果run方法执行完,则停止;
4、线程常用操作方法
(1)线程的命名与取得
实际开发中为了获取一些线程,只能通过线程名称来获得;
class XC implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
public class MyThread {
public static void main(String args[]) throws InterruptedException, ExecutionException {
XC xc = new XC();
new Thread(xc,"xiancheng1").start();
new Thread(xc).start();
}
}
如果存在耗时任务,可以交给线程处理,优先处理任务一和任务二;
public static void main(String args[]) throws InterruptedException, ExecutionException {
System.out.println("任务1");
new Thread(()->{
for(int x = 0;x<Integer.MAX_VALUE;x++) {
}
}).start();
System.out.println("任务2");
}
(2)线程休眠
休眠结束自动唤醒,多线程并不是同时休眠和唤醒,是存在时间差的;
public static void main(String args[]) throws InterruptedException, ExecutionException {
System.out.println("任务1");
new Thread(()->{
for(int x = 0;x<2;x++) {
try {
Thread.sleep(1000);//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务...");
}
}).start();
System.out.println("任务2");
}
(3)线程中断
public static void main(String args[]) throws InterruptedException, ExecutionException {
Thread thread = new Thread(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
if(!thread.isInterrupted()) {//判断未中断
thread.interrupt();//中断线程
}
}
(4)线程强制执行
某时候一个线程独占资源,需要强制执行;
public static void main(String args[]) throws InterruptedException {
Thread thread = new Thread(()->{
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.join(); //强制中断
}
(5)线程礼让
让出资源,别的线程先执行,每次礼让之让出一次当前资源;
public static void main(String args[]) throws InterruptedException {
Thread thread = new Thread(()->{
for(int x = 0;x<3;x++) {
try {
if(x== 0) {
Thread.yield(); //线程礼让
}
Thread.sleep(100);
System.out.println("ha:"+x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
for(int x = 0;x<3;x++) {
try {
Thread.sleep(100);
System.out.println("hei:"+x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(6)线程优先级
理论上优先级越高,越先执行,但不一定最先执行默认创建的线程为中等优先级。
通过int类型数字设置优先级,有以下优先级:;
MAX_PRIORITY: 10;
NORM_PRIORITY: 5;
MIN_PRIORITY: 1;
-
设置优先级
-
获取优先级
public static void main(String args[]) throws InterruptedException {
Thread thread = new Thread(()->{
for(int x = 0;x<3;x++) {
try {
Thread.sleep(100);
System.out.println("ha:"+x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
thread.setPriority(Thread.MAX_PRIORITY);//设置优先级
thread.getPriority();//获取优先级
}
5、线程的同步与死锁
当多个线程访问统一资源的时候,由于延迟等其他问题,导致线程数据不同步。
class XC implements Runnable{
private int number = 10;
@Override
public void run(){
while(true) {
// synchronized(this) {
if(this.number > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("已售票数:"+this.number--);
} else {
System.out.println("票已售光");
break;
}
// }
}
}
}
public class MyThread {
public static void main(String args[]) throws InterruptedException {
XC a = new XC();
new Thread(a,"A").start();
new Thread(a,"B").start();
new Thread(a,"C").start();
}
}
结果:
已售票数:9
已售票数:8
已售票数:10
已售票数:7
已售票数:6
已售票数:5
已售票数:4
已售票数:3
已售票数:2
已售票数:1
票已售光
已售票数:0
票已售光
已售票数:-1
票已售光
(1)同步
- 解决线程同步问题的关键是锁,当其中一个线程操作时,其他线程等待。
- 利用关键字synchronized来实现,定义方法或代码块,里面的代码只允许一个线程执行。
class XC implements Runnable{
private int number = 10;
@Override
public void run(){
while(true) {
synchronized(this) {//关键字,代码块
if(this.number > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("已售票数:"+this.number--);
} else {
System.out.println("票已售光");
break;
}
}
}
}
}
public class MyThread {
public static void main(String args[]) throws InterruptedException {
XC a = new XC();
new Thread(a,"A").start();
new Thread(a,"B").start();
new Thread(a,"C").start();
}
}
结果:
已售票数:10
已售票数:9
已售票数:8
已售票数:7
已售票数:6
已售票数:5
已售票数:4
已售票数:3
已售票数:2
已售票数:1
票已售光
票已售光
票已售光
- 但是同步代码块会导致程序使用性能降低,此时需要同步方法解决,在同步方法上加上关键字synchronized即可。
class XC implements Runnable{
private int number = 10;
@Override
public void run(){
this.scal();
}
public synchronized void scal() {//关键字,方法
while(true) {
// synchronized(this) {//关键字,代码块
if(this.number > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"已售票数:"+this.number--);
} else {
System.out.println("票已售光");
break;
}
// }
}
}
}
public class MyThread {
public static void main(String args[]) throws InterruptedException {
XC a = new XC();
new Thread(a,"A").start();
new Thread(a,"B").start();
new Thread(a,"C").start();
}
}
同步都会造成性能下降。
(2)死锁
- 开发中出现的一种不确定状态,线程都在等待对方让出资源;
- 若干线程访问同一资源时需要进行同步处理,过多的同步处理会造成死锁;
6、生产者与消费者模型
概念:
- 生产者负责信息内容生产,当生产完成一个完整信息后,由消费者进行消费;
- 如果生产者没有生产完成整个信息,消费者需要等待生产完成,反之如果消费者没有消费完成,生产者需要等待消费完成之后生产;