目录
线程
线程和进程的关系
进程是操作系统分配资源的最小单位
线程是一个进程内部的最小执行单元
1.一个进程可以包含多个线程,一个线程只能属于一个进程,线程不能脱离进程而独立运行
2.每一个进程至少包含一个线程(称为主线程),在主线程中开始执行程序, java程序的入口main()方法就是在主线程中被执行的。
3.在主线程中可以创建并启动其它的线程, 一个进程内的所有线程共享该进程的内存资源
线程中的常用方法
创建线程的三种方式
1.继承Thread类
示例
public class MyThread extends Thread { @Override public void run() { /* 在线程中要执行的任务全部写在run方法中 Thread类是java中提供对线程进行管理的类 */ for (int i = 0; i <1000 ; i++) { System.out.println("第"+i+"次"); } } }
public class Demo1 { public static void main(String[] args) { System.out.println("main方法开始"); //创建线程 MyThread myThread=new MyThread(); myThread.start();//启动线程 System.out.println("main方法结束"); } }
2.实现Runnable接口
实现Runnable的好处 1.避免了单继承的局限性 2.多个线程可以共享同一个接口实现类的对象,适合多个相同线程来处 理同一份资源
示例
public class Test implements Runnable{
/*
线程任务类
*/
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(Thread.currentThread().getName()+"第"+i+"次");
}
}
}
public class Demo2 {
public static void main(String[] args) {
Test test=new Test();
Thread thread=new Thread(test);//创建线程
thread.start();
Thread thread1=new Thread(test);//创建线程
thread1.start();
}
}
3.实现Callable接口
1.call()方法相比run()方法,可以有返回值
2.方法可以抛出异常
3.支持泛型的返回值
4.需要借助FutureTask类,获取返回结
示例
import java.util.concurrent.Callable;
public class Sum implements Callable<Integer> {
/*
线程的第三种创建方式
*/
@Override
public Integer call() throws Exception {
int i=0;
for (int j = 0; j < 10; j++) {
i+=j;
}
return i;
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) {
Sum sum=new Sum();
FutureTask<Integer> futureTask=new FutureTask(sum);//接收任务
Thread thread=new Thread(futureTask);//创建线程
thread.start();//开启线程
try {
Integer i=futureTask.get();//接收返回值
System.out.println(i);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
常用方法
setPriority(int):设置线程的优先级别,可选范围1-10,默认为5
static sleep(long):让当前的线程休眠并且指定毫秒数
static yield();线程主动让步,让出CPU的执行权.可以直接进入就绪队列中
join():线程让步
run()线程任务执行的方法,在线程中要执行的任务
start()启动线程
currentThread()获取当前线程(静态)
getName() 获取线程名字
getPrionty()获取优先级
setName() 设置线程名字
线程状态
新建
当一个Thread类或其子类的对象被声明并创建时,新生的线程对 象处于新建状态
就绪
处于新建状态的线程被start()后,将进入线程队列等待CPU时 间片,此时它已具备了运行的条件,只是没分配到CPU资源
运行
当就绪的线程被调度并获得CPU资源时,便进入运行状态,run ()方法定义了线程的操作和功能
阻塞
在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态
死亡
线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束
守护线程
只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
示例:
public class DaemonTest {
public static void main(String[] args) {
Demo demo=new Demo();
DaemonThread daemonThread=new DaemonThread();
demo.start();
daemonThread.setDaemon(true);//设置为守护线程
daemonThread.start();
}
}
public class DaemonThread extends Thread{
@Override
public void run() {
for (int i = 0; i <10000 ; i++) {
System.out.println("守护线程");
}
}
}
public class Demo extends Thread{
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(i);
}
}
}
多线程
什么时候用到多线程
1.程序需要同时执行两个或多个任务。 2.程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、 网络操作、搜索等。
多线程的优点
-
提高程序的响应.
-
提高CPU的利用率. ,压榨硬件的价值
-
改善程序结构,将复杂任务分为多个线程,独立运行
并发
在同一个时间点上,多个事情依次发生
并行
在同一个时间段内,多个事情同时执行
线程安全
多个线程用同一个资源
解决
排队+锁
1.几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作; 2.为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
synchronized锁
1.是一个关键字
2.可以修饰代码块和方法
3.隐式锁同步代码块执行完毕或者出现异常会自动释放
4.修饰方法时,非静态:锁对象是this, 静态:锁对象是当前类的class对象
模拟售票:
1.实现接口
public class PrintTicket implements Runnable {
int num = 10;
@Override
public void run() {
while (true) {
synchronized (this) {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + num);
num--;
} else break;
}
}
}
}
public class Test {
public static void main(String[] args) {
PrintTicket printTicket=new PrintTicket();
Thread thread=new Thread(printTicket,"窗口1:");
Thread thread1=new Thread(printTicket,"窗口2:");
thread.start();
thread1.start();
}
}
2.继承Thread
public class Demo1 extends Thread{
static int num=10;
static Object object=new Object();
@Override
public void run() {
while (true) {
synchronized (object) {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + num--);
}
else break;
}
}
}}
public class TestDemo1 {
public static void main(String[] args) {
Demo1 demo1=new Demo1();
demo1.setName("窗口1:");
Demo1 demo2=new Demo1();
demo2.setName("窗口2:");
demo1.start();
demo2.start();
}
}
Lock锁
1.是一个类
2.只能修饰方法块
3.要手动的添加释放锁
示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Lock1 implements Runnable{
int num=10;
Lock lock=new ReentrantLock();
@Override
public void run() {
while (true) {
{
try {
lock.lock();//添加锁
if (num > 0) {
System.out.println(Thread.currentThread().getName() + num--);
}
else break;
}
finally {
lock.unlock();//释放锁
}
}
}
}
}
public class LockTest1 {
public static void main(String[] args) {
Lock1 lock1=new Lock1();
Thread thread=new Thread(lock1,"窗口1:");
Thread thread1=new Thread(lock1,"窗口2:");
thread.start();
thread1.start();
}
}
线程通信
线程通讯指的是多个线程通过相互牵制,相互调度,即线程间的相互作用
生产者消费者示例
//柜台:
public class Counter {
int i=0;
public synchronized void add(){
while (true){
if(i==0){
i=1;
System.out.println("生产者添加了一个");
this.notify();
}else {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public synchronized void take(){
while(true){
if(i!=0){
i=0;
System.out.println("消费者用掉了一个");
this.notify();
}else {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
//生产者
public class Productor extends Thread{
Counter counter;
public Productor(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
counter.add();
}
}
//消费者
public class Customer extends Thread {
Counter counter;
public Customer(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
counter.take();
}
}
//测试
public class Test {
public static void main(String[] args) {
Counter counter=new Counter();
Productor productor=new Productor(counter);
Customer customer=new Customer(counter);
productor.start();
customer.start();
}
}
交替打印100之内的数
public class PrintDemo implements Runnable{
int i=0;
@Override
public void run() {
synchronized (this){
while(true){
this.notify();
System.out.println(Thread.currentThread().getName()+":"+i++);
if(i>=100){
break;
}
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args) {
PrintDemo printDemo=new PrintDemo();
Thread thread=new Thread(printDemo);
Thread thread1=new Thread(printDemo);
thread.start();
thread1.start();
}
}