线程概述
进程:计算机中特定功能的程序在数据集上的一次运行。
线程:线程是进程的一个单元。
多线程:一个进程中有多个线程在同时运行,如迅雷下载,迅雷软件的一次运行就是一个进程,那么在迅雷中可以同时下载多个电影,这就是多线程(每一个下载都是一个线程)
Jvm是多线程,在我们运行的时候后台会运行垃圾回收的线程,来清理没有被引用的对象
1.线程的创建方式
1.子类要重写run方法
package cn.tx.demo;
public class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
/**
* 线程执行的逻辑体
*/
public void run(){
for(int i = 1;i <= 100 ; i++){
//为线程取一个名字
System.out.println(name+"下载了"+i+"%");
}
}
}
2.测试代码
package cn.tx.demo;
public class ThreadTest {
public static void main(String[] args) {
//这就是一个线程
//System.out.println("helloword");
//创建一个线程对象
MyThread mt = new MyThread("肖申克的救赎");
//启动线程
mt.start();
MyThread mt1 = new MyThread("当幸福来敲门");
//启动线程
mt1.start();
//System.out.println("方法结束");
}
}
1.2实现runnable接口来创建线程
示例代码
package cn.tx.demo1;
/**
* 实现线程
* @author 李文辉i的电脑
*
*/
public class DownLoad implements Runnable{
private String name;
public DownLoad(String name){
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 1;i <= 100 ; i++){
//为线程取一个名字
System.out.println(name+"下载了"+i+"%");
}
}
}
测试代码
package cn.tx.demo1;
public class ThreadTest {
public static void main(String[] args) {
//创建线程对象
Thread t = new Thread(new DownLoad("当幸福来敲门"));
Thread t1 = new Thread(new DownLoad("肖申克的救赎"));
t.start();
t1.start();
}
}
2.线程的执行原理
线程的并发执行通过多个线程不断地切换CPU地资源,这个速度非常快,我们感知不到,我们能感知的就是三个线程在并发的执行
3.线程的生命周期
1.新建:线程被new出来
2.准备就绪:线程具有执行的资格,即线程调用了start(),没有执行的权力,
3.运行:具有执行的资格和具备执行的权力
4.阻塞:没有执行的资格和执行的权力
5.销毁:线程的对象变成垃圾,释放资源![]
6.解决并发synchronized (name)
4.解决线程的并发问题
package cn.tx.demo2;
/**
* 这是卖票的窗口类,我们创建了4对象就是4个窗口
* @author 李文辉i的电脑
*
*/
public class SaleTicketThread extends Thread{
private String name;
/**
* 定义共享的数据100张
*/
static int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
static Object obj = new Object();
public SaleTicketThread(String name){
this.name = name;
}
public void run(){
//买票是持续的
while(true){
//这个方法很有可能出现线程并发问题
synchronized (obj) {
if(tickets > 0){
System.out.println(name+"卖出座位是"+(tickets--)+"号");
}else{
break;
}
}
int millis = 200;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("卖票结束");
}
}
4.1.第二种解决方法,将对象方法设为共享
package cn.tx.demo3;
public class SaleTicket implements Runnable{
/**
* 窗口的名字
*/
/**
* 多线程共享的票
*/
int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
Object obj = new Object();
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
if(saleTickets()){
break;
}
//这个方法很有可能出现线程并发问题
synchronized (obj) {
if(tickets > 0){//Thread.currentThread().getName()共享的数据
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
break;
}
}
int millis = 200;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"卖票结束");
}
/*public boolean saleTickets(){
boolean isFinsh = false;
synchronized (obj) {
if(tickets > 0){//Thread.currentThread().getName()共享的数据
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinsh = true;
}
return isFinsh;
}
}*/
/**
* 如果一个对象方法上有synchronized的话那么锁的对象就是this
* @return
*/
public synchronized boolean saleTickets(){
//将方法设置为同步代码块
//synchronized (obj) {
boolean isFinsh = false;
if(tickets > 0){//Thread.currentThread().getName()共享的数据
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinsh = true;
}
return isFinsh;
//}
}
}
4.2类方法在线程上的使用、
package cn.tx.demo6;
/**
* 这是卖票的窗口类,我们创建了4对象就是4个窗口
* @author 李文辉i的电脑
*
*/
public class SaleTicketThread extends Thread{
private String name;
/**
* 定义共享的数据100张
*/
static int tickets = 100;
//创建一个锁对象,这个对象是多个线程对象共享的数据
static Object obj = new Object();
public SaleTicketThread(String name){
super(name);
this.name = name;
}
public void run(){
//买票是持续的
while(true){
//这个方法很有可能出现线程并发问题
//synchronized (obj) {
if(saleTickets()){
break;
}
int millis = 200;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("卖票结束");
}
//ThreadTest在本类中有四把锁,没有使用共同的锁,这样程序就会有问题
/**
* 解决方法将synchronized定义为类方法,那么这个锁就属于这个类
* 这样就只要一把锁了
* @return
*/
public static synchronized boolean saleTickets(){
//将方法设置为同步代码块
//synchronized (obj) {
boolean isFinsh = false;
if(tickets > 0){//Thread.currentThread().getName()共享的数据
System.out.println(Thread.currentThread().getName()+"卖出座位是"+(tickets--)+"号");
}else{
isFinsh = true;
}
return isFinsh;
//}
}
}
5.休眠
在做服务器端的程序的时候都需要给一个休眠的时间,在没有synchronized代码块里面会让出cup的资源
package cn.tx.demo7;
import java.util.Date;
public class DemoTest {
public static void main(String[] args) {
/**
* 设置休眠时间这样服务器的性能就会大大降低
* 但是能节省资源
*/
while(true){
System.out.println(new Date());
int millis = 1000;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
休眠在同步代码块内不会让出cpu资源
synchronized(obj){
int millis = 1000;
try {
//我们休眠如果在synchronized内就不样了内部不会让出cpu资源
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
线程间的通信
生产者生成水果没有被买走那么就不生产处于等待状态,如果水果被消费者买走的时候消费者会通知生产者告诉他我们已经把水果买走了请生产,消费者同类,如果水果已经生产出来那么就买走,买走之后再通知生产者水果已经没了请生产。
注意:
1.线程间的通信共享数据一定要有同步代码块synchronized
2.一定要有wait和notify,而且二者一定是成对出现
3.生产者和消费者的线程实现一定是while(true)里面
第一种实现方式,篮子
package cn.tx.demo9;
public class Basket {
private boolean isEmpty;
//建立两个篮子
public boolean isEmpty(){
return isEmpty;
}
public void setEmpty(boolean empty){
isEmpty = empty;
}
}
生产者
package cn.tx.demo8;
public class Producer extends Thread{
private Basket basket;
public Producer(Basket basket){
//super();
this.basket = basket;
}
public void run(){
while(true){
//定义一个同步代码块
synchronized(basket){
//线程等待的状态,或线程挂起
try {
if(!basket.isEmpty()){
basket.wait();//等待
}
System.out.println("生产水果");
//通知在这个共享对象上等待的线程
basket.setEmpty(false);
//通知在这个共享对象上
basket.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
int millis = 1000;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
消费者
package cn.tx.demo8;
public class Consumer extends Thread{
private Basket basket;
public Consumer(Basket basket){
//super();
this.basket = basket;
}
public void run(){
while(true){
//定义一个同步代码块
synchronized(basket){
//线程等待的状态,或线程挂起
try {
if(basket.isEmpty()){
basket.wait();//等待
}
System.out.println("消费水果");
//通知在这个共享对象上等待的线程
basket.setEmpty(true);
basket.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
int millis = 1000;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
测试类
package cn.tx.demo8;
public class Test {
public static void main(String[] args) {
Basket basket = new Basket();
Producer producer = new Producer(basket);
Consumer consumer = new Consumer(basket);
//启动线程
producer.start();
consumer.start();
}
}
第二种实现方式
package cn.tx.demo9;
public class Basket {
private boolean isEmpty;
//建立两个篮子
public boolean isEmpty(){
return isEmpty;
}
public void setEmpty(boolean empty){
isEmpty = empty;
}
}
生产者
package cn.tx.demo9;
public class Producer implements Runnable{
private Basket basket;
public Producer(Basket basket){
//super();
this.basket = basket;
}
public void run(){
while(true){
//定义一个同步代码块
synchronized(basket){
//线程等待的状态,或线程挂起
try {
if(!basket.isEmpty()){
basket.wait();//等待
}
System.out.println("生产水果");
//通知在这个共享对象上等待的线程
basket.setEmpty(false);
//通知在这个共享对象上
basket.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
int millis = 1000;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
消费者
package cn.tx.demo9;
public class Consumer implements Runnable{
private Basket basket;
public Consumer(Basket basket){
//super();
this.basket = basket;
}
public void run(){
while(true){
//定义一个同步代码块
synchronized(basket){
//线程等待的状态,或线程挂起
try {
if(basket.isEmpty()){
basket.wait();//等待
}
System.out.println("消费水果");
//通知在这个共享对象上等待的线程
basket.setEmpty(true);
basket.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
int millis = 1000;
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
测试类
package cn.tx.demo9;
public class Test {
public static void main(String[] args) {
Basket basket = new Basket();
Producer producer = new Producer(basket);
Consumer consumer = new Consumer(basket);
//启动线程
Thread t = new Thread(producer);
Thread t1 = new Thread(consumer);
t.start();
t1.start();
}
}
线程的优先级
可以通过public final void setRriority(int newPriority)
来设置线程的优先级,但是优先级并不是绝对的,只是相对来说比其他的线程得到cpu的资源机会多一些
在大数据中机会多,那么大多数就是机会多的哪一个
加入线程
join线程会抢先拿到cpu来执行线程,然后其他的线程再来执行
void join() 等待该线程终止
守护线程
package cn.tx.demo13;
/**
* 守护线程
* @author 李文辉i的电脑
*
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread mt = new MyThread("肖申克的救赎");
mt.setDaemon(true);//将mt设置为子线程下面就是主线程,当主线程结束,子线程也就结束了
mt.start();
System.out.println("主线程结束");//代码执行到这里mt的遍历消失
}
}
死锁
在做线程开发的时候要避免死锁
锁
package cn.tx.demo14;
public class Lock {
static Object lock1 = new Object();
static Object Lock2 = new Object();
}
进入锁
package cn.tx.demo14;
public class DeadLock extends Thread{
int flag;
public void run(){
if(flag == 1){
synchronized (Lock.lock1){
System.out.println("进入锁1");
synchronized (Lock.Lock2){
System.out.println("进入锁一中的锁二");
}
}
}else{
synchronized (Lock.Lock2){
System.out.println("进入锁2");
synchronized (Lock.lock1){
System.out.println("进入锁二中的锁一");
}
}
}
}
}
测试
package cn.tx.demo14;
public class DeadLockTest {
public static void main(String[] args) {
DeadLock dt = new DeadLock();
dt.flag = 1;
DeadLock dt1 = new DeadLock();
dt.start();
dt1.start();
}
}