线程和进程
要想说线程,首先必须得聊聊进程,因为线程是依赖于进程存在的。
进程概述
什么是进程呢?通过任务管理器我们就可以看到进程的存在。
概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
每一个进程都有它自己的内存空间和系统资源。
多进程的意义
单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。
Thread类的基本获取和设置方法
public final String getName()//获取线程名称
public final void setName(String name)//设置线程名称
其实通过构造方法也可以给线程起名字
思考:
如何获取main方法所在的线程名称呢?
public static Thread currentThread()//获取当前执行的线程
我们现在是想获取主线程的名称,那么我们可不可以先获取到主线程,
如果我们能获取到主线程,那么我们就可以调用getName方法获取对应的名称.
如何获取主线程呢? public static Thread currentThread()返回对当前正在执行的线程对象的引用。
获取线程的优先级:
public final int getPriority()返回线程的优先级。
线程的默认优先级是5
给线程设置优先级:
public final void setPriority(int newPriority)
线程休眠: public static void sleep(long millis) 线程休眠
举例:
th1.setPriority(Thread.MAX_PRIORITY);//10
th2.setPriority(Thread.MIN_PRIORITY);//1
th3.setPriority(Thread.NORM_PRIORITY);//5
加入线程: public final void join()
意思就是: 等待该线程执行完毕了以后,其他线程才能再次执行
注意事项: 在线程启动之后,在调用方法
礼让线程: public static void yield(): 暂停当前正在执行的线程对象,并执行其他线程。(其实在执行时这个效果并不明显)
守护线程: public final void setDaemon(boolean on):
将该线程标记为守护线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。 守护线程就立马死掉
该方法必须在启动线程前调用。
在代码中主线程可以当成是用户线程,如果这些子线程设置为守护线程那么只要主线程退出那么子线程也会直接退出。
中断线程
public final void stop(): 停止线程的运行
public void interrupt(): 中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞
注意:
Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了,之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。
方式一:
class thread extends Thread {
@Override
public void run() {
System.out.println(" = "+this.getName());
}
}
class test{
public static void main(String[] args) {
thread thread = new thread();
thread thread1 = new thread();
thread thread2 = new thread();
thread.setName("qin");
thread.start();
thread1.start();
thread2.start();
}
}
方式二:
class thread implements Runnable {
@Override
public void run() {
System.out.println(" = "+Thread.currentThread().getName());
}
}
class test{
public static void main(String[] args) {
thread thread = new thread();
Thread thread1 = new Thread(thread);
Thread thread2 = new Thread(thread);
Thread thread3 = new Thread(thread);
thread1.start();
thread2.start();
thread3.start();
}
}
方式三:
实现步骤
1. 创建一个类实现Callable 接口 重新里面的call()方法
2. 创建一个FutureTask类将Callable接口的子类对象作为参数传进去
3. 创建Thread类, 将FutureTask对象作为参数传进去
4. 开启线程*/
MyCallable myCallable = new MyCallable(1000);
//FutureTask 这个类里面能够获取线程执行完之后的返回的结果
FutureTask integerFutureTask = new FutureTask(myCallable);
Thread thread = new Thread(integerFutureTask);
thread.start();
//获取到 子线程执行完之后的结果
Integer integer = integerFutureTask.get();
System.out.println(integer);
public class MyCallable implements Callable<Integer> {
int num;
public MyCallable(int i) {
num=i;
}
call 方法 就是线程来执行的
@Override
public Integer call() throws Exception {
Thread thread = Thread.currentThread();
String name = thread.getName();
int sum=0;
for (int i = 1; i <=num; i++) {
//System.out.println(name+"=="+i);
sum+=i;
}
return sum;
}
}
当然也可以使用匿名类部类来实现。
FutureTask futureTask = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
return null;
}
});
Thread thread1 = new Thread(futureTask);
Thread thread2 = new Thread(futureTask);
Thread thread3 = new Thread(futureTask);
thread1.start();
Object o = futureTask.get();
System.out.println("o = " + o);
Files.copy(Paths.get("C:\\Users\\ShenMouMou\\Music\\我的图片和音乐\\音乐\\辛晓琪 - 领悟.mp3"), Paths.get("F:\\myMusic.mp4"));
同步代码块的格式
格式:
synchronized(对象){
需要同步的代码;
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能
1:同步的好处: 同步的出现解决了多线程的安全问题。
2:同步的弊端: 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,
因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识。
java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。
线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。
获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,
当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,
直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,
但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,
类锁是用于类的静态方法或者一个类的class对象上的。
我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,
所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。
但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,
它只是用来帮助我们理解锁定实例方法和静态方法的区别的.
1:案例演示: 同步代码块的锁问题
2:同步方法: 就是把同步关键字加到方法上
3:案例演示: 同步方法的锁对象是什么呢?
4:案例演示: 如果是静态方法,同步方法的锁对象又是什么呢?
同步代码块的锁对象: 任意一个对象
同步方法的锁对象: 是this
静态同步方法的锁对象:就是当前类对应的字节码文件对象
同步方法的格式:
就是在方法中加上synchronized关键字他的锁是this
private synchronized void maipiao(){}
Lock锁的概述
虽然我们可以理解同步代码块和同步方法的锁对象问题,
但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock和ReentrantLock
void lock()
void unlock()
案例演示:Lock锁的使用
static Lock lock=new ReentrantLock();
lock.lock();
try {
if (piao > 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
//System.out.println(1/0);
System.out.println("已经出售" + (piao--) + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
public class MyThread extends Thread {
private boolean flag;
public MyThread(boolean b) {
this.flag = b;
}
@Override
public void run() {
if (flag) {
synchronized (ObjectUtils.objA) {
System.out.println("true 进来了,持有objA");
synchronized (ObjectUtils.objB) {
System.out.println("true 进来了,持有objB");
}
}
} else {
synchronized (ObjectUtils.objB) {
System.out.println("false 进来了,持有objB");
synchronized (ObjectUtils.objA) {
System.out.println("false 进来了,持有objA");
}
}
}
}
}
public class ObjectUtils {
//定义两把锁对象
public static final Object objA=new Object();
public static final Object objB = new Object();
}
public class MyTest {
public static void main(String[] args) {
MyThread th1 = new MyThread(true);
MyThread th2 = new MyThread(false);
th1.start();
th2.start();
}
}
原文:https://www.cnblogs.com/project-zqc/p/11854859.html