Java中的线程可以分类:用户线程;守护线程
正常创建的线程是用户线程
守护线程与用户线程功能是一样的,去完成某件事情
用户线程的工作做完后它就结束了,守护线程是等待所有的用户线程结束后,守护线程才会自动退出
例如垃圾回收任务就是在一个守护线程中进行的
public class ThreadDemo extends Thread{
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
public class ThreadDemo1 extends Thread {
@Override
public void run() {
while(true)
{
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(Thread.currentThread().getName());
}
}
}
public class demo {
public static void main(String[] args) {
ThreadDemo t1 = new ThreadDemo();
t1.setName("用户线程");
t1.start();
ThreadDemo1 t2 =new ThreadDemo1();
t2.setName("守护线程");
t2.setDaemon(true);//将线程设置为守护线程,必须在启动线程前设置,否则会报错
t2.start();
}
}
多线程
在一个应用程序中可以有多个线程任务执行
程序中同时需要执行多个任务时,就需要多个线程。例如360安全卫士
多线程优点:
提高程序速度
提高了CPU的利用率
改善程序结构
多线程缺点:
多线程对内存消耗增高
多线程切换执行,对cpu的要求也提高了 这两个缺点可以通过升级硬件设备解决
多个线程访问同一个共享资源,会出现线程安全问题
出现线程安全问题:多线程且访问同一个共享资源(单一的多线程不会出现线程安全问题,每一个线程都在做自己的事情,没有交集)
线程并行执行:多个人同时做不同的事情,互补干扰
线程并发执行:在一段时间内依次执行某件事情,一个一个来做交替做、
必须程序控制线程 并发执行 高并发 双十一 秒杀 抢购...
卖票:买电影票 美图,支付宝,电影院 2.12 万达 1号 15:00 5排5号
解决线程安全问题:加锁+排队 为出票加锁,一次只能有一个线程进入到出票的方法中。
synchronized关键字 可以修饰代码块
synchronized(同步锁对象)
{
}
synchronized修饰方法 如果是非静态方法,那么锁对象是this;如果是静态方法,那么锁对象是类的Class对象
第一个的1和2是一个方法的不同写法,第二个的1和2也是,但是第一个和第二个方法不同,表达的意思相同
1.public class ticketThread_abck extends Thread{
static int num = 10;
static Object obj = new Object();
@Override
public void run() {
while (true) {
/*
* synchronized(锁对象)锁对象可以是任何对象,但是必须是唯一的,也就是多个线程对应同一个锁对象
* 在对象中,有一个区域叫对象头,对象头中有一个锁的标志为,无锁和已被使用
* */
synchronized (obj) {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
} else {
System.out.println("票卖完了");
break;
}
}
}
}
}
2.public class ticketThread extends Thread {
static int num = 10;
static Object obj = new Object();
@Override
public void run() {
while (true) {
print();
if(num == 0)
{
System.out.println("票卖完了");
break;
}
}
}
/*
synchronized 修饰方法时,锁对象默认是this
synchronized 修饰的是static 方法,那么锁对象是类的class对象
每一个类被加载到内存时,就会为类创建一个class类的对象,无论创建了多少个对象,class对象只有一个
* */
public static synchronized void print()
{
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}
}
}
public class tickettext {
public static void main(String[] args) {
ticketThread t1 = new ticketThread();
t1.setName("窗口1");
t1.start();
ticketThread t2 = new ticketThread();
t2.setName("窗口2");
t2.start();
}
}
1.package Day17.ticket2;
public class TicketThread implements Runnable {
int num =10;//这就是共享资源
@Override
public void run() {
while(true)
{
print();
if(num <= 0)
{
System.out.println("票卖完了");
break;
}
}
}
public synchronized void print() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}
}
}
2.public class TickThread_back implements Runnable { int num =10;//这就是共享资源 @Override public void run() { while(true) { synchronized (this) { if (num > 0) { System.out.println(Thread.currentThread().getName() + ":" + num); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } num--; } else { System.out.println("票卖完了"); break; } } } }}
synchronized是靠底层指令控制实现
synchronized可以修饰代码块,修饰方法,注意锁对象(锁对象可能会变)。
synchronized加锁方式是隐式的,进入到同步代码块时,自动获取锁 同步代码块执行完后,自动释放锁。
lock接口
lock锁是靠Java代码来控制
ReentrantLock类实现lock接口 可以来控制与synchronized相同的功能 但两者的实现细节完全不同的。
lock加锁只能对某一段代码加锁 而且是显式的加锁和释放锁
import java.util.concurrent.locks.ReentrantLock;
public class TicketThread implements Runnable{
int num = 10;//这就是共享资源
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":" + num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
} else {
System.out.println("票卖完了");
break;
}
}finally {
lock.unlock();//释放锁 尽量放在finally代码块中
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建一个出票任务
TicketThread t = new TicketThread();//只创建了一个线程任务对象
//支付宝 微信 不可能直接操作你的银行账号 向银行申请访问接口 实际操作的功能是银行
Thread t1 = new Thread(t,"窗口1");
t1.start();
Thread t2 = new Thread(t,"窗口2");
t2.start();
}
}
线程死锁
不同的线程分别占用对方需要的同步资源不放弃,
出现死锁,发送死锁后不会报错,只是等待
锁的嵌套时容易发生死锁
线程通信
就是多个线程之前相互牵制,制约运行
wait() 让线程等待,调用wait()方法后线程进入到阻塞阻塞状态,必须通过另一个线程唤醒
notify() 唤醒等待中的线程
notifyAll() 唤醒等待中所以线程
这3个方法必须在同步代码中执行
sleep()
wait()
相同点:可以让线程进入到阻塞状态
不同点:
sleep() 是Thread类中的方法
不会释放锁
休眠时间到了后,会自动进入到就绪状态
wait()是Object类中的方法
会释放锁
wait后的线程,需要使用notify/notifyAll唤醒
生产者和消费者问题
两个线程之间相互牵制使用
生产者线程
柜台中的商品 0
消费者线程
/*
* 柜台*/
public class Counter {
int num = 0;
/*
* 生产者调用
* */
public synchronized void jia(){
if(num==0)
{
num++;
System.out.println("生产者生产了一个商品");
this.notify();
}else
{
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
* 消费者调用*/
public synchronized void jian()
{
if(num==1)
{
num--;
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() {
while(true)
{
counter.jia();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
* 消费者*/
public class Custom extends Thread{
Counter counter;
public Custom(Counter counter)
{
this.counter = counter;
}
@Override
public void run() {
while(true)
{
counter.jian();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class test {
public static void main(String[] args) {
Counter counter =new Counter();//共享数据
Productor productor = new Productor(counter);
productor.start();
Custom custom = new Custom(counter);
custom.start();
}
}
第三者创建线程的方式
继承Thread 还是实现Runnable 最终都是重写run().
run方法没有返回值,也不能抛出异常 就存在局限性
java中推出了一个新接口 Callable 里面定义了一个Call()方法 可以有返回值(使用泛型自定义),可以抛出异常
import java.util.concurrent.Callable;
public class SumThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
Thread.sleep(100);
for (int i = 1; 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) {
SumThread sumThread = new SumThread();
FutureTask<Integer> futureTask = new FutureTask(sumThread);
Thread t = new Thread(futureTask);
t.start();
try {
Integer sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}