1.程序,进程,线程
程序:为完成某种特定的功能,使用计算机语言编写的一系列指令的集合,即静态代码
进程:运行中的程序是操作系统分配资源的最小单位
线程:线程是进程内部最小的执行单元(具体要做的一件事情)是操作系统进任务调度的最小单元
早期cpu执行是以进程为单位
后来cpu执行改为以更小的线程为单位.
一个程序内部有多个线程(任务),只需要切换线程即可
2.线程和进程的关系
一个进程中可以包含多个线程的
线程必须属于某一个进程,不能独立存在
一个进程中必须有一个主线程,在主线程中可以创建其他子线程
一个进程中的所有线程,都共享该进程的资源
创建线程:
1.继承Thread类
注意:此处测试可以看到运行结果MyThread和main交叉执行
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("MyThread:"+i);
}
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//myThread.run(); 仍是一个进程,没有创建新进程,仍按从上到下的顺序依次执行
myThread.start();//创建新进程
for (int i = 0; i < 1000; i++) {
System.out.println("main:"+i);
}
}
}
2.实现Runnable接口
public class RunTask implements Runnable{
@Override
public void run() {
//此处需要重写的是需要执行的任务
for (int i = 0; i < 1000; i++) {
System.out.println("RunTask:"+i);
}
}
}
public class Test {
public static void main(String[] args) {
RunTask runTask = new RunTask();//创建任务对象
Thread thread = new Thread(runTask);//创建新线程,再将任务对象交给线程对象
thread.start();
for (int i = 0; i <1000 ; i++) {
System.out.println("main:"+i);
}
}
}
public class RunTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getId());
System.out.println(Thread.currentThread().getName());
}
}
public class Test {
public static void main(String[] args) {
RunTask runTask = new RunTask();
Thread thread = new Thread(runTask,"李亚鹏");//为线程执行的任务命名
thread.start();
System.out.println(Thread.currentThread().getId());//对现在正在执行的线程进行操作
System.out.println(Thread.currentThread().getName());//获取信息(id 名字)
}
}
区别:
继承Thread类之后,java中只能进行单继承,所以不能再继承其他类,比较局限
在实现Runnable接口之后,还可以继承其他类
Thread类中方法:
run();用来写线程需要执行的任务
start();用来执行线程
Thread(runTask);用来给线程赋予执行的任务
Thread(runTask,“mythread”);用来给线程赋予执行的任务,同时给线程命名
currentThread();现在正在执行的线程
getId();获取现在正在执行线程的id
getName();获取现在正在执行线程的名字
程序优先级:
public class RunTask implements Runnable{
@Override
public void run() {
System.out.println("thread");
}
}
public class Test {
public static void main(String[] args) {
RunTask runTask = new RunTask();
Thread thread = new Thread(runTask,"李亚鹏");//为线程执行的任务命名
thread.start();
//由于操作系统是综合性调度,所以高优先级也不一定是先执行 只是先获取cpu处理的可能性变大
thread.setPriority(Thread.MAX_PRIORITY);//设置优先级,最大为10,最小为1,默认是5
System.out.println(thread.getPriority());
System.out.println(Thread.currentThread().getPriority());//main方法的线程优先级
}
}
线程状态:
守护线程:
注意:设置线程为守护线程必须在启动线程之前,否则会跑出一个
IllegalThreadStateException异常。
public class DaemonThread extends Thread{
@Override
public void run() {
int a = 0;
while (true){
System.out.println("thread:"+ a++);
}
}
}
public class Test {
public static void main(String[] args) {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);//守护线程
daemonThread.start();
for (int i = 0; i < 100; i++) {
System.out.println("main:"+i);
}
}
}
多线程:
什么情况需要多线程:
多线程的优点:
多线程的缺点:
线程同步:
public class TicketThread extends Thread{
/*
synchronized关键字:
修饰代码块:
需要在synchronized(同步对象)
要求: 多个线程对应的是同一个对象 用对象头中的一块区域记录线程有没有进入同步代码块中
修饰方法:
当同步锁修饰方法时,方法静态,那此时默认锁对象的是该类的Class对象(包含该类中的所有信息)
当不是静态方法时,同步锁默认锁对象是this
*/
static int num = 10;
//static Object obj = new Object();
public static synchronized void PrintTicket(){
//当同步锁修饰方法时,方法静态,那此时默认锁对象的是该类的Class对象(包含该类中的所有信息)
//当不是静态方法时,同步锁默认锁对象是this
if (num>0){
System.out.println(Thread.currentThread().getName()+":"+num);
num--;
}
}
@Override
public void run() {
/* while (true){
synchronized (obj){
if (num>0){
System.out.println(Thread.currentThread().getName()+":"+num);
num--;
}else{
break;
}
}
}*/
while (true){
if (num==0){
break;
}
PrintTicket();
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread t1 = new TicketThread();
t1.setName("窗口1");
t1.start();
TicketThread t2 = new TicketThread();
t2.setName("窗口2");
t2.start();
}
}
上锁除了synchronized之外还有Lock
import java.util.concurrent.locks.ReentrantLock;
public class TicketThread extends Thread{
static int num = 10;
static ReentrantLock lock = new ReentrantLock();
//lock主动上锁 主动解锁
//synchronized 靠底层代码默认上锁解锁
@Override
public void run() {
while (true){
lock.lock();//上锁
if (num==0){
break;
}
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+":"+num);
num--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread ticketThread1 = new TicketThread();
ticketThread1.setName("窗口1");
TicketThread ticketThread2 = new TicketThread();
ticketThread2.setName("窗口2");
ticketThread1.start();
ticketThread2.start();
}
}
线程死锁:
死锁,做个比喻就是一个中国人和一个外国人吃饭
中国人需要的是两只筷子,外国人需要的是一把刀和一个叉子
恰好现在中国人拿了一只筷子一把刀,外国人拿了一个叉子一只筷子
俩人大眼瞪小眼,等着对方把自己需要的餐具还给自己。
那这顿饭就吃不了了,你不给我我也不给你,一顿僵持。
专业的话来说就是:
注意:小编目前的代码水平在日常生活中还暂时没有多少概率遇到死锁问题,所以为了方便大家了解,此处我们人为编写一个死锁程序。
public class DieLockDemo extends Thread{
boolean flag;
static Object objA = new Object();
static Object objB = new Object();
public DieLockDemo(boolean flag){
this.flag = flag;
}
@Override
public void run() {
if (flag){
synchronized (objA){
System.out.println("if objA");
synchronized (objB) {
System.out.println("if objB");
}
}
}else {
synchronized (objB){
System.out.println("else objB");
synchronized (objA){
System.out.println("else objA");
}
}
}
}
}
下方是test程序:
public class Test {
public static void main(String[] args) {
DieLockDemo dieLockDemo1 = new DieLockDemo(true);
Thread t1 = new Thread(dieLockDemo1);
t1.start();
DieLockDemo dieLockDemo2 = new DieLockDemo(false);
Thread t2 = new Thread(dieLockDemo2);
t2.start();
}
}
注意:如果第一次没有出现死锁情况,可以多试几遍哦。这是操作系统的锅,我可不背。
线程通信:
public class WaitDemo extends Thread{
static int num = 1;
static Object object = new Object();
/*
wait()是Object类中定义的方法,必须用同步对象调用,让线程等待,必须再度唤醒才能继续执行
notify()Object类中定义的方法,必须用同步对象调用,唤醒被wait的线程
notifyAll()是Object类中定义的方法,必须用同步对象调用,用来唤醒所有被wait的线程
三个方法都必须在同步代码块中执行
*/
@Override
public void run() {
while (true){
if (num<=100){
synchronized (object){
object.notify();//唤醒等待的线程
System.out.println(Thread.currentThread().getName()+":"+num);
num++;
try {
object.wait();//让进来的线程等待,同时释放锁,可以让其他线程进来
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class Test {
public static void main(String[] args) {
WaitDemo waitDemo1 = new WaitDemo();
waitDemo1.start();
WaitDemo waitDemo2 = new WaitDemo();
waitDemo2.start();
}
}
此处涉及到的是wait()方法 ,notify()方法
wait()是Object类中定义的方法,必须用同步对象调用,让线程等待,必须再度唤醒才能继续执行 notify()Object类中定义的方法,必须用同步对象调用,唤醒被wait的线程 notifyAll()是Object类中定义的方法,必须用同步对象调用,用来唤醒所有被wait的线程 三个方法都必须在同步代码块中执行
我用我的话来说就是:
wait()出现,那么现在进入同步锁的线程就处于阻塞状态,同时这个锁被打开了,可以让别的线程前来执行任务。
与sleep()不同的是:wait之后的线程放手了,其他的线程也有机会执行任务了。但是sleep就是属于“占着茅坑不拉屎”,它休眠了,锁没解开,其他的进程着急也进不来。【牛马sleep】
notify()就是属于唤醒优先级较高的wait进程(如果就一个wait进程那当然只叫一个啦,那还用说),“哥们别睡了,一会该你上了!”
那么notifyAll()就是唤醒所有wait进程。
新增创建线程方式
特点:
import java.util.concurrent.Callable;
public class SumTask implements Callable<Integer> {
//Callable 有返回值 可以抛出异常
@Override
public Integer call() throws Exception {
int sum = 0 ;
for (int i = 0; i < 10; i++) {
sum+=i;
}
return sum;
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) {
SumTask sumTask = new SumTask();
FutureTask<Integer>futureTask = new FutureTask<>(sumTask);
Thread thread = new Thread(futureTask);
thread.start();
try {
Integer sum = futureTask.get();
//get()获取该返回值
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
OK,那么今天的小葵花妈妈课堂就结束啦!孩子学习老不好,多半是废了,没收手机就好了。
see u~~~~