一、什么是线程
线程是独立调度和分派的基本单位,它被包含在进程之中,是进程中的实际运作单位
二、什么是进程
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
一个进程可以包含有多个线程
三、java多线程的实现方式
1、实现方法简述
| 方法一 | 方法二 |
|---|---|
| 继承Thread类,重写run()方法,执行start()方法启动多线程 | 普通类实现Runnable接口,重写run()方法,启动时,使用Thread类装载线程对象,最后使用start方法启动(方法二比较常用,因为java类是单继承的,尽量使用接口) |
2、实例
方法一:继承Thread类,重写run()方法,执行start()方法启动多线程
/**
* @description 线程测试类,使用第一种实现方式
* 第一步 继承Thread类
* 第二步重写run()方法
* 第三步执行start()方法启动多线程
* @version 1.0
* @author manyu
* @address www.mpmanyu.com
* @update 2021年3月26日 下午10:51:59
*
*/
public class TestThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("i="+i);
};
}
}
TestThread1类自己建立一个,内容相同
创建进程启动类
/**
* @description 测试线程,同时运行TestThread1 ,TestThread2 两个类的对象
* @version 1.0
* @author manyu
* @address www.mpmanyu.com
* @update 2021年3月26日 下午11:05:11
*
*/
public class ThreadWindows {
public static void main(String[] args) {
//第一个线程对象
TestThread1 test1 = new TestThread1();
//第二个线程对象
TestThread2 test2 = new TestThread2();
//同时启动test1 与 test2
test1.start();
test2.start();
}
}
执行结果如下
i=9
i=10
j=0
i=11
j=1
i=12
i=13
i=14
.......
方法二:普通类实现Runnable接口,使用Thread类装载线程对象,最后使用start方法启动(方法二比较常用,因为java类是单继承的,尽量使用接口)
代码如下:
建立ThreadDemo3 ThreadDemo4两个类,内容相同
/**
* @ClassName: ThreadDemo3
* @Description: 使用第二种方式启动线程
* 实现Runnable接口,装载线程,启动线程
* @author: manyu
* @date: 2021年3月27日 上午10:43:10
*/
public class ThreadDemo3 implements Runnable{
/* (non-Javadoc)
* @see java.lang.Runnable#run()
* 使用第二种方式启动线程
*/
@Override
public void run() {
for(int i =0;i<1000;i++) {
System.out.println("第二种方式启动 i="+i);
Thread.yield();
}
}
}
建立启动类
/**
* @ClassName: ThreadWindow
* @Description: 使用第二种方式启动多线程
* @author: manyu
* @date: 2021年3月27日 上午8:06:56
*/
public class ThreadWindow2 {
/**
* @Title: main
* @Description: 使用第二种方式启动线程
* @param args
* @author manyu
* @update 2021年3月27日上午8:06:56
*/
public static void main(String[] args) {
//创建thread3对象
ThreadDemo3 threadDemo3 = new ThreadDemo3();
Thread thread3 = new Thread(threadDemo3);
thread3.start();
//创建thread4对象
ThreadDemo4 threadDemo4 = new ThreadDemo4();
Thread thread4 = new Thread(threadDemo4);
thread4.start();
}
}
四、java线程安全问题
1、线程安全问题出现的前提
当多个线程操作同一共享数据的时候,就会产生线程安全问题。
2、如何解决线程安全问题
给共享数据加锁,使用synchronized (类.class)
例如:卖票小案例
售票系统类说明:TicketDemo类是卖票的线程类,共200张票,不同的站点进行卖票,假设完成一次售票需要10ms时间。
/**
* @ClassName: TicketDemo
* @Description: 购票软件实例 共有200张票,n个售票窗口进行售票
* @author: manyu
* @address: www.mpmanyu.com
* @date: 2021年3月27日 下午4:04:02
*/
public class TicketDemo implements Runnable {
private static int TICKETNUM = 200; //一共有200张票
@Override
public void run() {
try {
for(int i = 2000; i>0;i--) {
//必须给售票的整个过程加锁,保证一个线程处理完成后才能后下一个线程进行卖票
synchronized (TicketDemo.class) {
if(TICKETNUM>0) {
TICKETNUM--;
System.out.println("剩余票数="+TICKETNUM);
Thread.sleep(10);//假设一次售票需要10ms
}
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
窗口类说明:WindowThread类是窗口类,模拟多个窗口同时售票。如果要所有的售票点能够正常售票,不要超卖。造成 售票量>总票量(200),必须在给整个的售卖过程加锁。
/**
* @ClassName: WindowThread
* @Description: 售票测试的窗口测试程序
* @author: manyu
* @address: www.mpmanyu.com
* @date: 2021年3月27日 下午4:09:46
*/
public class WindowThread {
public static void main(String[] args) {
//窗口1
TicketDemo win1 = new TicketDemo();
Thread win1Thread = new Thread(win1);
//窗口2
TicketDemo win2 = new TicketDemo();
Thread win2Thread = new Thread(win2);
//窗口3
TicketDemo win4 = new TicketDemo();
Thread win4Thread = new Thread(win4);
//窗口4
TicketDemo win5 = new TicketDemo();
Thread win5Thread = new Thread(win5);
//开始售票
win1Thread.start();
win2Thread.start();
win4Thread.start();
win5Thread.start();
}
}
3、run()与start()方法的区别
run()方法相当于调用普通方法,它是顺序执行,实际还是单线程;
start()方法真正启动线程,