文章目录
前言
本文讲解一下Java高级特性中的多线程。
一、进程和线程
进程
进程是程序的一次动态执行过程,它有如下特点:
1.进程是系统运行程序的基本单位
2.每一个进程都有自己独立的一块内存空间、一组系统资源
3.每一个进程的内部数据和状态都是完全独立的
线程
线程是进程中执行运算的最小单位,一个进程在其执行过程中可以产生多个线程,而线程必须在某个进程内执行,线程和进程既有联系又有区别:
1.一个进程中至少要有一个线程
2.资源分配给进程,同一进程的所有线程共享该进程的所有资源
3.处理机分配给线程,即真正在处理机上运行的是线程
二、进程的5种状态
三、线程的创建方式
继承Thread类
package com.zhenghou.hello4;
/**
* 1,继承Thread类创建线程
*
* */
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i+":"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread t=Thread.currentThread();
System.out.println(t.getName());
//设置线程名称为hello
t.setName("hello");
System.out.println(t.getName());
t.run();
}
}
运行结果
main
hello
Process finished with exit code 0
实现Runnable接口
package com.zhenghou.hello4;
public class MyThread1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(i+":"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
MyThread1 myThread1=new MyThread1();
Thread thread=new Thread(myThread1);
thread.start();
System.out.println("线程就绪");
thread.run();
System.out.println("线程运行");
}
}
运行结果
线程就绪
0:main
1:main
2:main
3:main
4:main
线程运行
0:Thread-0
1:Thread-0
2:Thread-0
3:Thread-0
4:Thread-0
Process finished with exit code 0
二者之间的比较
继承Thread类:
编写简单,可直接操作线程
适用于单继承
实现Runnable接口:
避免单继承局限性(java属于单继承)
便于共享资源
四、线程的常用方法
join()方法和sleep()方法
package com.zhenghou.hello4;
public class MyThread7 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
try {
//休眠 sleep
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
MyThread7 myThread7 = new MyThread7();
Thread thread = new Thread(myThread7);
thread.start();
for (int i = 0; i <20 ; i++) {
if(i==5){
//强制执行
try {
//强制执行
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"运行:"+i);
}
}
}
setPriority()方法
public static void main(String[] args) {
Thread thread1 = new Thread(new MyThread6(),"AAA");
Thread thread2 = new Thread(new MyThread6(),"bbbb");
//设置权限
thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);
System.out.println(thread1.getPriority());
System.out.println(thread2.getPriority());
}
yield()方法
package com.zhenghou.hello4;
public class MyThread5 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"运行"+i);
if(i==3){
//礼让
Thread.yield();
System.out.println("礼让");
}
}
}
public static void main(String[] args) {
Thread thread1=new Thread(new MyThread5());
Thread thread2=new Thread(new MyThread5());
thread1.start();
thread2.start();
}
}
五、start和run的区别
start和run的主要区别在于线程的启动方式不同。调用start()方法会在一个新的线程中启动run()方法,而直接调用run()方法会在当前线程中执行run()方法。如果你希望通过线程来执行代码,应该使用start()方法来启动一个新的线程并执行run()方法。
六、线程同步的实现
package com.zhenghou.hello5;
public class Demo1 implements Runnable{
@Override
public void run() {
int count1=0;//年轻人次数
int count2=0;//老年人次数
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"爬完100米!");
if(Thread.currentThread().getName().equals("年轻人")){
count1++;
}else {
count2++;
}
if(count1==10){
System.out.println("年轻人到达终点");
}
if(count2==10){
System.out.println("老年人到达终点");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
Thread thread1=new Thread(new Demo1(),"年轻人");
Thread thread2=new Thread(new Demo1(),"老年人");
thread1.start();
thread2.start();
}
}
七、锁的使用
举个例子:在生活中的买票中,使用的就是多线程。但是如果没有上锁的话,可能两个人会买到同一张票,因此为了避免这种情况的发生,我们引入了锁的概念。
package com.zhenghou.hello5;
public class Windows1 implements Runnable{
private static int ticket=5; //三个窗口共享5张票
@Override
public void run() {
while (true){
//上锁
synchronized (Windows1.class){
if (ticket > 0){
try {
Thread.sleep(500); //模拟网络延迟
} catch (Exception e) {
e.printStackTrace();
}
ticket--;
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"号票。");
}else {
System.out.println("你来晚了,票已售光!");
break;
}
}
}
}
public static void main(String[] args) {
Windows1 w1 = new Windows1();
Thread t1 = new Thread(w1,"窗口1");
Thread t2 = new Thread(w1,"窗口2");
Thread t3 = new Thread(w1,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
八、线程的通信
Java提供了如下三个方法实现线程之间的通信:
1.wait():调用wait()方法会挂起当前线程,并释放共享资源的锁
2.notify():调用任意对象的notify()方法会在因调用该对象的wait()方法而阻塞的线程中随机选择一个线程解除阻塞,但要等到获得锁之后才可以真正执行
3.notifyall():调用了notifyall()方法会将因调用该对象的wait()方法而阻塞的所有线程一次性全部解除阻塞
总结
本文讲解了Java高级特性中的多线程,在我们现实生活中也会遇到很多多线程的例子。但是在我们的开发中,小的公司一般很少用多线程,大的公司一般用多线程用的比较多,但是多线程在我们的面试中也是高频问点,我们还是要熟练掌握的。