@
进程就是正在运行的程序,是操作系统运行程序是产生的,它是独立存在的,进程之间互不干扰。
线程是进程的一个子集,是进程中的实际运作单位,开发人员可以通过操作线程进行多处理器编程。
1)在耗时的操作时使用线程,可以提高程序运行的速度
2)在并行操作时使用线程,提高并行的速度
3)多CPU系统中使用线程,提高CPU利用率
4)改善程序结构,对一个程序进行拆分,降低程序执行难度
5)进程之间的通信十分不方便,同一个进程中的线程可以进行数据共享
在 java 中实现线程的方式有 2 种,一种是继承 Thread,一种是实现 Runnable 接口。
class MyThread extends Thread{
private int ticket = 5;
public void run(){
for (int i=0;i<10;i++)
{
if(ticket > 0){
System.out.println("ticket = " + ticket--);
}
}
}
}
public class ThreadDemo{
public static void main(String[] args){
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
运行结果:
ticket = 5
ticket = 4
ticket = 5
ticket = 5
ticket = 4
ticket = 3
ticket = 2
ticket = 1
ticket = 4
ticket = 3
ticket = 3
ticket = 2
ticket = 1
ticket = 2
ticket = 1
每个线程单独卖了5张票,即独立的完成了买票的任务,但实际应用中,比如火车站售票,需要多个线程去共同完成任务,在本例中,即多个线程共同买5张票。
class MyThread implements Runnable{
private int ticket = 5;
public void run(){
for (int i=0;i<10;i++)
{
if(ticket > 0){
System.out.println("ticket = " + ticket--);
}
}
}
}
public class RunnableDemo{
public static void main(String[] args){
MyThread my = new MyThread();
new Thread(my).start();
new Thread(my).start();
new Thread(my).start();
}
}
运行结果:
ticket = 5
ticket = 2
ticket = 1
ticket = 3
ticket = 4
在第二种方法(Runnable接口实现多线程)中,买票输出的顺序并不是54321,这是因为线程执行时会被抢占资源,所以输出结果不唯一。ticket并不是原子操作。
区别一:
Runnable是使用实现接口的方式来实现多线程的,Thread是通过继承的方式来实现多线程的
Runnable实现接口的方式更好,推荐使用,主要原因是因为实现接口的方式有利于解耦,方便代码的维护工作
区别二:
Java只支持“接口”的多继承,不支持“类“”的多继承;而继承在java中具有单根性,子类只能继承一个父类,一句话就是单继承多实现
区别三:
Runnable增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
区别四:
Runnable适合多个相同程序的线程区处理同一资源的情况
public class SynchronizedDemo implements Runnable {
private String name;
static Integer count = 20;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Integer getCount() {
return count;
}
public static void setCount(Integer count) {
SynchronizedDemo.count = count;
}
public SynchronizedDemo() {
}
public SynchronizedDemo(String name) {
this.name = name;
}
@Override
public void run() {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
if (count > 0) {
count--;
System.out.println(Thread.currentThread() + " 开始吃苹果, 还剩" + count + "个苹果");
}
}
}
}
}
public Test {
public static void main(String[] args) {
SynchronizedDemo sd = new SynchronizedDemo();
new Thread(sd, "光头强").start();
new Thread(sd, "熊大").start();
new Thread(sd, "熊二").start();
}
}
运行结果:
"C:\Program Files\Java\jdk-11.0.9\bin\java.exe"
Thread[光头强,5,main] 开始吃苹果, 还剩4个苹果
Thread[熊二,5,main] 开始吃苹果, 还剩3个苹果
Thread[熊大,5,main] 开始吃苹果, 还剩2个苹果
Thread[熊大,5,main] 开始吃苹果, 还剩1个苹果
Thread[熊二,5,main] 开始吃苹果, 还剩0个苹果
public class SynchronizedDemo implements Runnable {
private String name;
static Integer count = 5;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Integer getCount() {
return count;
}
public static void setCount(Integer count) {
SynchronizedDemo.count = count;
}
public SynchronizedDemo() {
}
public SynchronizedDemo(String name) {
this.name = name;
}
@Override
public synchronized void run() {
while (count > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count > 0) {
count--;
System.out.println(Thread.currentThread() + " 开始吃苹果, 还剩" + count + "个苹果");
}
}
}
}
public Test {
public static void main(String[] args) {
SynchronizedDemo sd = new SynchronizedDemo();
new Thread(sd, "光头强").start();
new Thread(sd, "熊大").start();
new Thread(sd, "熊二").start();
}
}
运行结果:
"C:\Program Files\Java\jdk-11.0.9\bin\java.exe"
Thread[光头强,5,main] 开始吃苹果, 还剩4个苹果
Thread[熊二,5,main] 开始吃苹果, 还剩3个苹果
Thread[熊大,5,main] 开始吃苹果, 还剩2个苹果
Thread[熊大,5,main] 开始吃苹果, 还剩1个苹果
Thread[熊二,5,main] 开始吃苹果, 还剩0个苹果
(1)wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
(2)sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
(3)notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
(4)Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
以上就是对多线程的总结了,代码仅供参考,欢迎讨论交流。
原文:https://www.cnblogs.com/zzvar/p/14604469.html