进程:就是正在执行的程序,加载到程序内存中运行
线程:进程可进一步划分为线程
举例:在自己电脑上安装了微信,就是程序 当运行微信,被加载到内存中,分配空间,就是进程,微信进程中包括许多小的任务就是线程
进程和线程的关系:一个进程可以包括多个线程,一个线程只属于一个进程,线程不能脱离线程的存在,每个进程最少包括一个线程(主线程),Java中,main为主线程.所有线程共享资源.
多线程:在一个进程中,同时拥有多个线程,执行多个任务
何时需要多线程:在一个进程中,同时执行两个或多个任务
多线程的优点:提高程序的响应,提高CPU的利用率,改善程序结构
多线程的缺点:多线程对同一个共享资源进行访问,会出现各种不正常情况 解决办法:线程同步
首先要重写run方法,将在线程中要执行的代码写在写在run方法里面
public class ThreadDemo extends Thread{
//创建线程方式1 继承Thread类
/*
重写run方法 将在线程中需要执行的任务写在run方法里
*/
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("run:"+i);
}
}
然后在主线程中创建 在继承Thread类中首先就是要创建线程 即创建本身的对象
并启动其他线程 启动线程需要start方法
public class Test {
/*
main就是主线程 在主线程中创建并启动其他线程
*/
public static void main(String[] args) {
/*
在CPU中一个时间点只能处理一个线程,并且交替执行
*/
ThreadDemo t= new ThreadDemo();//创建线程
t.start();//启动线程线程,线程是独立的,可以由cpu加载执行
// t.run();在这run()就是普通方法的调用,不是启动线程
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
}
}
}
1.首先要重写run方法,将在线程中要执行的代码写在写在run方法里面
package com.lsy.javaThread.Day1.Demo2;
/*
创建线程方式二
实现接口Runable
*/
public class ThreadDemo implements Runnable{
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("run:"+i);
}
}
}
2.然后就是要创建一个线程要执行的任务
3.创建线程,并将需要执行的任务添加到线程中去
4.启动线程
package com.lsy.javaThread.Day1.Demo2;
public class Test {
public static void main(String[] args) {
//创建了一个线程要执行的任务
ThreadDemo t = new ThreadDemo();
//创建线程并将线程中需要执行的任务添加到线程中
Thread thread= new Thread(t);
thread.start();//启动线程
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
}
}
}
通常使用Runnable
好处:避免单继承,实现接口可以继承其他接口
多个线程可以共享同一个接口实现类的对象.非常适合多个相同线程来处理同一份资源.
run():将在线程中要执行的代码写在写在run方法里面
start():将线程启动
Thread构造方法:
Thread(Runnable target)将需要执行的任务添加到线程中去
Thread(Runnable target,String name)将需要执行的任务添加到线程中去,并为线程命名
Thread.currentThread() 获得当前正在执行的线程
getName() 获取到线程名称
**setName(名称)**为线程设置名称
计算机只有一个cpu,各个线程轮流获得cpu的使用权,才能执行任务
优先级高的线程有更多机会获得cpu机会
java中线程优先级一般有1~10表示,一般情况下.默认为5,但是也可以通过setPriority和getPriority方法来设置或返回优先级;
thread.setPriority(10);
thread1.setPriority(1);
cpu执行的策略
时间片:就是排队.先来先执行
抢占式:对优先级高的先执行
线程在它的生命周期处于不同的状态
启动线程 就绪状态等待cpu的加载
当线程获得cpu的执行权,进入到运行状态
当线程cpu执行权失去后(cpu还要执行其他线程),进入到就绪状态
当线程所有任务执行完,进入死亡状态
**新建:**当一个Thread类的对象声明并创建时,新生的线程处于新建状态
**就绪:**处于新建转态的线程被start()后,将进入线程队列等待cpu时间片,此时已经具备了运行的条件了,只是没被分配到cpu资源
**运行:**当就绪的线程被调度并获得cpu资源,进入运行状态,执行run方法里面的代码
**阻塞:**在某种特殊情况下,被人为挂起或执行输入输出操作时,让住cpu执行权
**死亡:**线程完成了它的全部工作或线程被提起强制性地终止或出现异常导致结束
**start()**线程开始
**sleep()**线程睡眠 通过Thread调用
**yield()**线程让出cpu执行权 通过Thread调用
**stop()**让线程进入消亡状态
**join()**等待指定线程执行完毕后,其他线程才执行 需注意要在另外一个线程start()前要调用此方法
package com.lsy.javaThread.Day2.Demo1;
public class ThreadDemo extends Thread {
public void run() {
for (int i = 0; i < 1000; i++) {
/*if (i % 5 == 0) {
Thread.yield();//线程主动让步,让出cpu执行权
}*/
/* try {
Thread.sleep(1000);//让线程进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
public static void main(String[] args) {
ThreadDemo t = new ThreadDemo();
t.setName("线程一");
t.start();
t.stop();
/* try {
t.join();//线程合并 等待t1线程执行完毕后,其他线程才执行
} catch (InterruptedException e) {
e.printStackTrace();
}*/
ThreadDemo t1 = new ThreadDemo();
t1.setName("线程二");
t1.start();
}
}
线程分为两种 守护线程和用户线程
**守护线程的作用:**守护线程的作用是为了其他线程的运行提供便利服务
守护线程和用户线程几乎没有区别,唯一区别就是在于虚拟机的离开,如果用户线程已经全部退出运行,只剩下守护线程存在,虚拟机也就退出了
**注意:**设置为守护线程必须在启动线程之前,否则会抛出异常
t.setDaemon(true);//设置为守护线程,当用户线程全部结束后,才会销毁
并发:多个cpu同时执行多个任务.多个人同时做不同的事
**并行:**一个cpu同时执行多个任务.多个人同时做一件事
多线同步多个线程同时读写同一份共享资源时,会引起冲突.所以引入线程同步,就是各个线程间要有先来后到
同步就是排队+锁
几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作
为了保证数据在方法中被访问时的正确性,在访问同时加入锁机制
例如买票案例
用synchronized修饰代码块
方法一:继承Thread类
package com.lsy.javaThread.Day4.demo1;
public class ThreadTicket extends Thread {
static int ticket = 10;
static Object obj = new Object();
public void run() {
while (true) {
synchronized (obj) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
}
}
}
package com.lsy.javaThread.Day4.demo1;
public class test {
public static void main(String[] args) {
ThreadTicket threadTicket1= new ThreadTicket();
threadTicket1.setName("窗口一");
ThreadTicket threadTicket2= new ThreadTicket();
threadTicket2.setName("窗口二");
threadTicket1.start();
threadTicket2.start();
}
}
方法二:实现Runnable接口
package com.lsy.javaThread.Day4.demo2.demo1;
public class ThreadTicket implements Runnable {
int ticket = 10;
Object obj = new Object();
public void run() {
while (true) {
synchronized (obj) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
}
}
}
package com.lsy.javaThread.Day4.demo2.demo1;
public class test {
public static void main(String[] args) {
ThreadTicket threadTicket1 = new ThreadTicket();
Thread t1 = new Thread(threadTicket1);
t1.setName("窗口一");
Thread t2 = new Thread(threadTicket1);
t2.setName("窗口二");
t1.start();
t2.start();
}
}
用synchronized修饰方法体
方法一:继承Thread类
package com.lsy.javaThread.Day4.demo1;
public class ThreadTicket extends Thread {
static int ticket = 10;
public void run() {
while (true) {
if (ticket > 0) {
Printticket();
} else {
break;
}
}
}
public static synchronized void Printticket (){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
}
}
}
package com.lsy.javaThread.Day4.demo1;
public class test {
public static void main(String[] args) {
ThreadTicket threadTicket1= new ThreadTicket();
threadTicket1.setName("窗口一");
ThreadTicket threadTicket2= new ThreadTicket();
threadTicket2.setName("窗口二");
threadTicket1.start();
threadTicket2.start();
}
}
方法二:实现Runnable接口
package com.lsy.javaThread.Day4.demo2.demo1;
public class ThreadTicket implements Runnable {
int ticket = 10;
Object obj = new Object();
public synchronized void run() {
while (true) {
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket--);
} else {
break;
}
}
}
}
package com.lsy.javaThread.Day4.demo2.demo1;
public class test {
public static void main(String[] args) {
ThreadTicket threadTicket1 = new ThreadTicket();
Thread t1 = new Thread(threadTicket1);
t1.setName("窗口一");
Thread t2 = new Thread(threadTicket1);
t2.setName("窗口二");
t1.start();
t2.start();
}
}
总结:继承Thread类和实现Runnable的区别就是继承Thread类在对共享资源要将其变成一份,即变为类对象,用static修饰 实现Runnable类在所有的共享资源只有一份,不用修饰
static 变量 随着类的加载而加载.生命周期比较长
非static 变量 生命周期与对象相同
**死锁:**不同的线程分别占用对方需要的同步资源不放弃,都在等待放弃自己需要的同步资源.形成线程的死锁
出现死锁后,不会出现异常,不会出现提示,只是所有的线程处于阻塞状态,无法继续
package com.lsy.javaThread.Day4.demo3;
public class ThreadDemo extends Thread{
static Object objA = new Object();
static Object objB = new Object();
boolean flag;
public ThreadDemo( boolean flag){
this.flag=flag;
}
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");
}
}
}
}
}
package com.lsy.javaThread.Day4.demo3;
public class Test {
public static void main(String[] args) {
ThreadDemo t1 =new ThreadDemo(true);
ThreadDemo t2 =new ThreadDemo(false);
t1.start();
t2.start();
}
}
从jdk5开始,java提供了更强大的线程同步机制-通过显示定义同步锁对象来实现同步,同步锁使用Lock对象充当.
synchronize和lock锁区别
1.lock锁是显示锁(手动开启和关闭锁)
synchronize是隐式锁,出了作用域自动释放
2.lock只有代码块锁,synchronize有代码块锁和方法锁,使用Lock锁,jvm将花费较少的时间来调度线程,性能更好.
3.线程同步优先使用顺序Lock>同步代码块>同步方法
线程通讯指的是多个线程通过消息传递实现相互牵制,相互调度
设计三个方法
wait一旦执行此方法,当前线程就会进入阻塞状态,并释放同步监视器
notify一旦执行此方法,就会唤醒别wait的一个线程
notifyAll唤醒所有被wait的线程
**注意:**wait notify notifyAll三个方法必须使用在同步代码块中
列如:两个线程交互打印100以内的数
package com.lsy.javaThread.Day4.Demo4;
public class Printnum implements Runnable{
Object obj = new Object();
int num=1;
@Override
public void run() {
while(true) {
synchronized (this) {
this.notify();
if (num<=100){
System.out.println(Thread.currentThread().getName()+":"+num++);
}
else {
break;
}
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Printnum printnum = new Printnum();
Thread thread = new Thread(printnum);
thread.setName("线程一");
Thread thread1 = new Thread(printnum);
thread1.setName("线程二");
thread.start();
thread1.start();
}
}
新增方式一:
**实现Callable接口:**与实现Runnable接口相比,Callable功能更强大些.
相比run()方法,可以有返回值
方法可以抛出异常
支持泛型的返回值
需要借助FutureTask类,获取返回结果
package com.lsy.javaThread.Day3.demo4;
import java.util.concurrent.Callable;
/*
新增创建线程方式
实现Callable接口与Runnable相比功能更强大
可以有返回值
可以向外界抛出异常
*/
public class ThreadDemo implements Callable<Integer> {
int sum=0;
@Override
public Integer call() throws Exception {
for (int i = 1; i <=100 ; i++) {
sum+=i;
}
return sum;
}
}
-----------------------------------------------------------
package com.lsy.javaThread.Day3.demo4;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();//创建任务
FutureTask<Integer> futureTask = new FutureTask<Integer>(threadDemo);//接受任务 使用它来接受返回值
Thread thread = new Thread(futureTask);
thread.start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
新增方式二
使用线程池
**背景:**经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
**思路:**提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
好处: 可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。提高响应速度(减少了创建新线程的时间),降低资源消耗(重复利用线程池中线程,不需要每次都创建),便于线程管理.
package com.lsy.javaThread.Day3.demo5.demo4;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
ThreadDemo sumNumThread = new ThreadDemo();
//将任务交给线程池中线程执行
executorService.submit(sumNumThread);//使用3个线程分别调用
executorService.submit(sumNumThread);
executorService.submit(sumNumThread);
executorService.submit(sumNumThread);
executorService.submit(sumNumThread);
executorService.submit(sumNumThread);
executorService.submit(sumNumThread);
Future<Integer> f = executorService.submit(sumNumThread);
try {
System.out.println(f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();//关闭线程池
}
}
-----------------------------------------------------------
package com.lsy.javaThread.Day3.demo5.demo4;
import java.util.concurrent.Callable;
/*
新增创建线程方式
实现Callable接口与Runnable相比功能更强大
可以有返回值
可以向外界抛出异常
*/
public class ThreadDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
System.out.println(Thread.currentThread().getName());
for (int i = 1; i <=100 ; i++) {
sum+=i;
}
return sum;
}
}