进程
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础;有独立的内存空间和系统资源
并行
指在同一时刻,有多条指令在多个处理器上同时执行。
并发
指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行
线程
定义:一个程序运行时的不同执行路径,进程执行过程中的最小单位
创建线程的方式:1.继承Thread类 2.实现Runnable接口
注意:Thread对象中的start()方法就是创建一个新的线程,并自动调用该线程中的run()方法;执行一个线程就是执行该线程的run()方法中的代码;一个Thread对象只能创建一个线程,一个线程不能调用两次start()方法;start()方法执行完只表示线程具有了被CPU执行的资格,CPU并一定会立即执行
/*
* 创建线程方式一:继承Thread类
*/
public class MyThreadOne extends Thread{
// run()方法内部编写线程任务
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// this.getName() 获取当前线程的名称
System.out.println(this.getName()+":"+(i+1));
}
}
}
/*
* 创建线程方式二:实现Runnable接口
*/
public class MyThreadTwo implements Runnable{
// run()方法内部编写线程任务
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// Thread.currentThread().getName() 获取当前线程的名称
System.out.println(Thread.currentThread().getName()+":"+(i+1));
}
}
}
public class Test {
public static void main(String[] args) {
// 1.创建线程对象
// 继承Thread类的线程直接创建线程对象
MyThreadOne t1 = new MyThreadOne();
t1.setName("线程一"); // 设置线程名称;线程默认有默认名称
// 实现了Runnable接口的类创建对象只是对象,需将对象发送给Thread类创建线程
MyThreadTwo two = new MyThreadTwo();
Thread t2 = new Thread(two);
t2.setName("线程二");
// 2.启动线程
t1.start();
t2.start();
/*
* main()方法是主线程,与子线程不冲突,此时主函数三个线程并发执行
*/
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":"+(i+1));
}
}
}
线程的调度:多个线程之间可以并发执行,也可以根据需要让一个线程等待另一个线程,或暂停一个线程。一般来说,线程的状态有就绪、执行、等待、阻塞、终止
1.sleep()方法
在指定时间内让当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用。
sleep()使当前线程进入阻塞状态,在指定时间内不会执行。
2.join方法
等待该线程终止。
等待调用join方法的线程结束,再继续执行。
3.yield方法
暂停当前正在执行的线程对象。
yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。
yield()只能使同优先级或更高优先级的线程有执行的机会。
public class T1 {
public static void main(String[] args) {
// 1.创建线程
MyThreadOne t1 = new MyThreadOne();
MyThreadTwo two = new MyThreadTwo();
Thread t2 = new Thread(two);
// 2.获取线程优先级
System.out.println("t1线程的优先级"+t1.getPriority());
System.out.println("t2线程的优先级"+t2.getPriority());
// 3.线程的最大、小优先级
System.out.println("线程的最大优先级"+Thread.MAX_PRIORITY);
System.out.println("线程的最小优先级"+Thread.MIN_PRIORITY);
// 4.设置优先级
t1.setPriority(8);
t2.setPriority(2);
// 5.启动线程
t1.start();
t2.start();
}
}
public class T2 {
public static void main(String[] args) throws InterruptedException {
// 创建线程
MyThreadOne t1 = new MyThreadOne();
MyThreadTwo two = new MyThreadTwo();
Thread t2 = new Thread(two);
// 开启线程
t1.start();
/*
* 当t1线程开启后,程序有两个线程,即主线程和t1线程
* 当主线程得到运行权限的时候,yield()会使当前线程进入就绪状态,即主线程从执行状态进入就绪状态
* 但是不一定就会执行t1线程,有可能主线程马上又进入到运行状态
*/
Thread.yield();
for (int i = 0; i < 10; i++) {
/*
* 当i等于1的时候开启t2线程
* 但是t2.start()和 t2.join()不一定会一起执行;
* 只有主线程得到运行权限,运行了join(),才会使t2线程一直执行
* 也就是说在start()和 join()之间,有可能切换到其他线程执行
*/
if(i==1){
t2.start();
t2.join();
}
if(i==4){
// 当i等于4的时候,当前线程睡眠5s,即主线程睡眠5s
Thread.sleep(5000);
}
System.out.println(Thread.currentThread().getName());
}
}
}
线程的同步
多个线程操作同一资源,并且要求这些操作中若干个操作不能被中断,这是就考虑到线程的同步的问题;
线程同步是通过synchronized来实现【修饰:a.代码块b.方法(默认锁定this)】
多个线程操作同一资源:
1.实现接口,将接口对象发送给多个线程
2.继承,需将共同操作的资源设置为静态
/*
* 线程模拟卖票
*/
public class Site implements Runnable {
private int ticket = 100; // 票数
private int count = 0; // 记录票
@Override
public void run() {
while (true) {
/*
* synchronized 锁定代码块:只要获取到了CPU执行权限,就必须执行完锁定的代码块
*/
synchronized (this) {
/*
* 切记:
* 1.不能将while循环也锁定在块中;会出现一个线程将整个循环执行完
* 2.不能将if选择锁在块外,会出现多个线程验证通过,导致出现卖超的现象
*/
if (ticket <= 0) {
break;
}
count++;
ticket--;
System.out.println(Thread.currentThread().getName() + "购买到了第"
+ count + "张票," + "剩余" + ticket + "张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class D1 {
public static void main(String[] args) {
/*
* 创建卖票资源对象,将一个对象发送个多个线程,使资源可以共享
* 线程之间操作的是一个共同的对象
*/
Site s = new Site();
Thread t1 = new Thread(s,"黄牛1");
Thread t2 = new Thread(s,"黄牛2");
Thread t3 = new Thread(s,"黄牛3");
t1.start();
t2.start();
t3.start();
}
}
线程的通信:
有时多个线程具有彼此相互协作才能完成某个功能 【实现方式: wait() 和 nofity()/nofityAll()】
wait()方法
在其他线程调用对象的notify或notifyAll方法前,导致当前线程等待。线程会释放掉它所占有的“锁标志”,从而使别的线程有机会抢占该锁。
当前线程必须拥有当前对象锁。如果当前线程不是此锁的拥有者,会抛出IllegalMonitorStateException异常。
唤醒当前对象锁的等待线程使用notify或notifyAll方法,也必须拥有相同的对象锁,否则也会抛出IllegalMonitorStateException异常。
waite()和notify()必须在synchronized中进行调用。如果在没有synchronized中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。