进程:
正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
线程:
是存在于进程中的,一个进程可以包含多个线程的。
单个线程是进程中的单个顺序控制流,或者说就是一个单独执行路径
一个进程如果只有一条执行路径,称之为单线程程序
一个进程如果包含多条执行路径,称之为多线程程序。
二、串行、并行、并发1、串行,指的是所有的任务都是按照先后顺序执行的,在前一个任务没处理完的情况下
是不会处理下一个任务的,就像理发店只有一个理发师,每个人剪头发的时候都需要
等待前面的人剪完。
2、并行,指的是将任务分给不同的处理器去处理,每一个处理器中的处理是串行,
比如火车站售票会有多个窗口。
3、并发,实质上是一种现象,并发需要处理器的支持,比如在处理一个任务的时候,操作系统
可以进行调度其他的任务,不论串行还是并行,都需要操作系统的支持并发。
假设喝水是一个任务,每个火车售票员在卖票的同时也能喝水,就说明支持并发。(单个cpu通过时间片执行任务)
思考题:
JVM启动的时候是单线程还是多线程的呢?
多线程。 主线程 ,垃圾回收线程 ,JVM在启动的时候,最低要求要有两个线程,JVM启动的时候是多线程。
三、thread的常用方法//获取当前线程的名字
Thread.currentThread().getName()
1.start():1.启动当前线程 2.调用线程中的run方法
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字,还可以通过构造方法设置:new Thread("名字")
6.yield():主动释放当前线程的执行权
7.join():在线程中插入执行另一个线程,该线程被阻塞,直到插入执行的线程完全执行完毕以后,该线程才继续执行下去
8.stop():过时方法。当执行此方法时,强制结束当前线程。
9.sleep(long millitime):线程休眠一段时间
10.isAlive():判断当前线程是否存活
11.守护线程和非守护线程
后台线程 public final void setDaemon(boolean on) (守护线程)
java中有两类线程:用户线程,守护线程
用户线程:我们再学习多线程之前的所有代码,运行起来的时候都是一个个的用户线程
守护线程:所谓的守护线程,指的就是程序运行的时候再后台提供一个通用的服务线程 ,比如说垃圾回收线程,它就是一个称职的守护线程,并且这个线程是程序不可或缺一部分 或者说只要程序存在非守护线程,程序就不会停止 如果一个程序都是守护程序,程序就停止了。(如果非守护线程结束,守护线程也需要停止)
四、线程的调度调度策略:
时间片:线程的调度采用时间片轮转的方式
抢占式:高优先级的线程抢占CPUJava的调度方法:1.对于同优先级的线程组成先进先出队列(先到先服务),使用时间片策略2.对高优先级,使用优先调度的抢占式策略
等级:MAX_PRIORITY:10 MIN_PRIORITY:1 NORM_PRIORITY:5
方法:getPriority():返回线程优先级
setPriority(int newPriority):改变线程的优先级
注意!:高优先级的线程要抢占低优先级的线程的cpu的执行权。但是仅是从概率上来说的,高优先级的线程更有可能被执行。并不意味着只有高优先级的线程执行完以后,低优先级的线程才执行。
五、线程实现的方式方式一、继承Thread类,重写run方法
public class Thread1 extends Thread{
private int tickets = 100;
@Override
public void run() {
if(tickets>0){
while (true){
if(tickets>0) {
System.out.println(getName() + "正在出售第" + tickets-- + "张票");
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Thread1 win1 = new Thread1();
win1.start();
}
}
方式二、实现runable接口,实现run方法
public class Thread1 implements Runnable {
private int tickets = 100;
@Override
public void run() {
while(true){
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");
} else {
break;
}
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread win1 = new Thread(thread1,"窗口一");
Thread win2 = new Thread(thread1,"窗口二");
Thread win3 = new Thread(thread1,"窗口三");
win1.start();
win2.start();
win3.start();
}
}
方式三、 自定义类实现Callable,实现call()方法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
//创建线程池对象
ExecutorService executorService = Executors.newFixedThreadPool(2);
//创建实现类对象
ThreadPool threadPool = new ThreadPool();
//提交任务
executorService.submit(threadPool);
executorService.submit(threadPool);
executorService.shutdown();
}
}
public class ThreadPool implements Callable {
private int tickets = 100;
@Override
public Object call() {
while(true){
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");
} else {
break;
}
}
}
return null;
}
}
六、实现线程安全的方式
1、synchronized关键字
(1)同步代码块的锁对象是谁呢?(修饰代码块)
任意对象,但是多个线程之间锁对象要一样
(2)同步方法?(修饰方法)
将synchronized关键字放到方法上
同步方法的锁对象是this
(3)静态方法的锁对象是谁呢?(修饰静态方法)
class文件,字节码文件对象也是属于一个Object类下面的对象
这个class文件不能是随便一个类的字节码文件
应该是run方法所在类的字节码文件
使用wait和notify方法必须建立在synchronized关键字上(也就是说必须要有锁,wait会释放锁)
2、lock锁在此之前我们解决线程同步安全问题的时候,使用的是synchronized关键字,通过分析
然后将哪些代码块给包起来,但是,我们并没有直接看到在哪里上了锁,或者说
在哪里释放了锁让其他线程获取到
为了更加清晰的表达如何加锁以及如何释放锁,JDK1.5之后提供了一个新的锁对象
Lock。
Lock(接口)
具体的子类:Class ReentrantLock
void lock() 加锁
void unlock() 释放锁
例子一
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockThreadDemo {
public static void main(String[] args) {
//创建一个锁对象
Lock lock = new ReentrantLock();
//创建线程实现类
LockThread lockThread1 = new LockThread(lock);
//创建线程
Thread win1 = new Thread(lockThread1, "窗口一");
Thread win2 = new Thread(lockThread1, "窗口二");
Thread win3 = new Thread(lockThread1, "窗口三");
win1.start();
win2.start();
win3.start();
}
}
import java.util.concurrent.locks.Lock;
public class LockThread implements Runnable {
private int tickets = 1000;
private Lock lock;
LockThread(Lock lock){
this.lock = lock;
}
@Override
public void run() {
while(true){
lock.lock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (tickets > 0) {
System.out.println(Thread.currentThread().getName()+ "正在出售第" + tickets-- + "张票");
} else {
break;
}
lock.unlock();
}
}
}
例子二
生产者消费者问题
public class GetBrand implements Runnable {
private Brand brand;
public GetBrand(Brand brand) {
this.brand = brand;
}
@Override
public void run() {
synchronized (brand){
while (true) {
if (brand.getNum() == 0) {
try {
brand.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
brand.setNum(brand.getNum() - 1);
System.out.println("有顾客买走了一个包子,现在有" + brand.getNum() + "个包子");
brand.notify();
}
}
}
}
public class SetBrand implements Runnable{
private Brand brand;
public SetBrand(Brand brand) {
this.brand = brand;
}
@Override
public void run() {
synchronized (brand) {
while (true) {
if (brand.getNum()>=20) {
try {
brand.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
brand.setNum(brand.getNum() + 1);
System.out.println("刚刚制作了一个包子,现在有" + brand.getNum() + "个包子");
brand.notify();
}
}
}
}
public class Brand {
private int num = 0;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
public class Test {
public static void main(String[] args) {
Brand brand = new Brand();
GetBrand getBrand = new GetBrand(brand);
SetBrand setBrand = new SetBrand(brand);
Thread thread = new Thread(getBrand);
Thread thread1 = new Thread(setBrand);
thread.start();
thread1.start();
}
}



