1 进程和线程
进程概述
什么是进程呢?通过任务管理器我们就可以看到进程的存在。
概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
多进程的意义
单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。
线程概述
在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位
多线程的意义
并行和并发
前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。
后者是物理上同时发生,指在某一个时间点同时运行多个程序。
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
JVM的启动是多线程的吗:
*我们启动线程使用不是run方法,而应该是start方法.使该线程开始执行;
Java 虚拟机调用该线程的 run 方法。
2 Thread类
public final String getName()//获取线程名称
public final void setName(String name)//设置线程名称 public static Thread currentThread()//获取当前执行的线程
public final int getPriority() //获取线程的优先级
public final void setPriority(int newPriority)//设置线程的优先级,线程的优先级的范围是: 1 - 10
public static void sleep(long millis) 线程休眠
public final void join() 加入线程:
public final void stop(): 停止线程的运行
public static void yield() 礼让线程: 暂停当前正在执行的线程对象,并执行其他线程
public void interrupt(): 中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞
public final void setDaemon(boolean on): 守护线程,将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。
mt1.setDaemon(true) ;//该方法必须在启动线程前调用。
mt2.setDaemon(true) ;
// 启动线程
mt1.start() ;
mt2.start() ;
注意事项: 有的时候我们给线程设置了指定的优先级,但是该线程并不是按照优先级高的线程执行,那是为什么呢?
* 因为线程的优先级的大小仅仅表示这个线程被CPU执行的概率增大了.但是我们都知道多线程具有随机性,
* 所以有的时候一两次的运行说明不了问题
public class MyThread extends Thread {
public MyThread(){}
public MyThread(String name){
super(name) ;
}
@Override
public void run() {
for(int x = 0 ; x < 100 ; x++){
System.out.println(Thread.currentThread().getName() + "----" + x);
}
}
}
---------------------------------------
// 创建线程对象
MyThread mt1 = new MyThread("张三") ;
MyThread mt2 = new MyThread("李四") ;
// public Thread(String name) 给线程设置名称
// 设置名称
//mt1.setName("张三") ;
//mt2.setName("李四") ;
// 启动线程
mt1.start() ;
mt2.start() ;
3 线程安全问题
A:首先想为什么出现问题?(也是我们判断是否有问题的标准)
是否是多线程环境
是否有共享数据
是否有多条语句操作共享数据
B:如何解决多线程安全问题呢?
把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。
4 Lock锁
public class MyThread implements Runnable {
private static int tickets = 100 ;
private static final Lock lock = new ReentrantLock() ;
@Override
public void run() {
while(true){
// 添加锁
lock.lock() ;
if(tickets > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (tickets--) + "张票");
}
// 释放锁
lock.unlock() ;
}
}
}
5 死锁问题
如果出现了同步嵌套,就容易产生死锁问题
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象
锁的概念
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,
因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识。
java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。
线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。
获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,
当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,
直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,
但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,
类锁是用于类的静态方法或者一个类的class对象上的。
我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,
所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。
但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,
它只是用来帮助我们理解锁定实例方法和静态方法的区别的.
6 总结
三种创建多线程方式
public class Mythread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
Mythread th = new Mythread();
th.setName("线程A");
th.start();
}
}
public class Mythread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Demo1 {
public static void main(String[] args) {
Mythread th = new Mythread();
Thread th1 = new Thread(th);
th1.setName("线程A");
th1.start();
}
}
7 编写程序,完成多个窗口共卖100张票的程序,并测试。
方法一
class MyThread extends Thread {
Object obj = new Object();
public static int ticket=100;
public MyThread (String s) {
super( s );
}
public void run() {
while(true){
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName()+"正在售出第" + (ticket--) + "张票");
}
}
}
}
}
测试类
class Test {
public static void main (String[] args) {
MyThread t1 = new MyThread("线程A");
MyThread t2 = new MyThread("线程B");
MyThread t3 = new MyThread("线程C");
t1.start();
t2.start();
t3.start();
}
}
方法二
class MyThread implements Runnable {
Object obj = new Object();
int ticket=100;
public void run() {
while(true){
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在售出第" + (ticket--) + "张票");
}
}
}
}
}
测试类
class Test {
public static void main (String[] args) {
MyThread t1 = new MyThread();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t1);
Thread thread3 = new Thread(t1);
thread1.setName("A");
thread2.setName("B");
thread3.setName("C");
thread1.start();
thread2.start();
thread3.start();
}
}
方法三
class MyThread implements Runnable {
Object obj = new Object();
int ticket=100;
public void run() {
while(true){
method();
}
}
private synchronized void method() {
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在售出第" + (ticket--) + "张票");
}
}
}