线程基本概念java
进程:内存中正在进行的一个程序多线程
线程:进程中的一个执行流程并发
多线程:有两个 或者 两个以上并发的执行流程ide
线程的生命周期,线程分为如下五种状态this
(阻塞) 暂停执行spa
sleep:等待多少毫秒;超过了以后回复就绪状态等待cpu调用执行
join:等待其余线程执行完,线程A调用了线程B的join();方法,那么线程A等线程B执行完再执行线程
线程图解:对象
主线程blog
当Java程序启动时,一个线程马上运行,该线程通 常叫作程序的主线程(main thread),==它是程序 开始时就执行的==。继承
主方法就是主线程的任务 main();
public class TestThreadMain {
public static void main(String[] args) {
// 得到当前的线程 主线程名字,优先级,主线程组
System.out.println(Thread.currentThread());//Thread[main,5,main]
System.out.println(Thread.currentThread().getName());//main
}
}
问题:启动一个java应用程序至少启动几个主线程?
会先启动两个线程:一个主线程,一个垃圾回收线程
子线程
默认的名字:Thread —— 数字
建立子线程
区别:
1. 继承Thread类,继承了Thread类的全部能够继承的;Runnable接口,只有run();
2. Runnable接口有利于资源共享
但愿主线程最后结束
/** 建立子线程示例代码 */
//建立子线程方法一:继承自Thread类
class MyThread extends Thread{
MyThread(String name){
super(name);
}
//子线程的任务功能在run中
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +":"+i);
}
}
}
//建立子线程方法二:实现Runnable 接口 用的较多,有利于资源共享
class ThreadDemo implements Runnable{
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +"吃饭");
}
}
}
public class TestThread1 {
public static void main(String[] args) {
// //建立一个线程对象
// Thread t = new Thread();
// //启动线程
// t.start();
// //建立一个子线程
// MyThread t1 = new MyThread("t1");//新建
// //启动子线程,必须用start,而且只能启动一次
// t1.start();//就绪
//不是线程对象
ThreadDemo demo = new ThreadDemo();
// 绑定ThreadDemo类对象
//Thread zhangsan = new Thread(demo);
Thread zhangsan = new Thread(demo,"张三");
Thread lisi = new Thread(demo,"李四");
//设置优先级
/* lisi.setPriority(10);
zhangsan.setPriority(1);*/
//最低,普通,最高 比直接赋予数字好一些
//1 5 10
zhangsan.setPriority(Thread.MAX_PRIORITY);
zhangsan.setPriority(Thread.MIN_PRIORITY);
zhangsan.setPriority(Thread.NORM_PRIORITY);
//启动线程
zhangsan.start();
lisi.start();
//但愿主线程最后结束方法一
/* try {
Thread.sleep(1000);//等1000毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}*/
////但愿主线程最后结束方法二:判断子线程是否运行
/* if(zhangsan.isAlive() || lisi.isAlive()){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
//但愿主线程最后结束方法三:让子线程都执行完才能恢复主线程
try {
zhangsan.join();
lisi.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
线程优先级
1 – 10
10最高
/** 建立子线程 */
//建立子线程方法一:继承自Thread类
class MyThread extends Thread{
MyThread(String name){
super(name);
}
//子线程的任务功能在run中
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +":"+i);
}
}
}
//建立子线程方法二:实现Runnable 接口 用的较多,有利于资源共享
class ThreadDemo implements Runnable{
@Override
public void run() {
for(int i = 1; i<= 3 ; i++){
System.out.println(Thread.currentThread().getName() +"吃饭");
}
}
}
public class TestThread1 {
public static void main(String[] args) {
// //建立一个线程对象
// Thread t = new Thread();
// //启动线程
// t.start();
// //建立一个子线程
// MyThread t1 = new MyThread("t1");//新建
// //启动子线程,必须用start,而且只能启动一次
// t1.start();//就绪
//不是线程对象
ThreadDemo demo = new ThreadDemo();
// 绑定ThreadDemo类对象
//Thread zhangsan = new Thread(demo);
Thread zhangsan = new Thread(demo,"张三");
Thread lisi = new Thread(demo,"李四");
//设置优先级
/* lisi.setPriority(10);
zhangsan.setPriority(1);*/
//最低,普通,最高 比直接赋予数字好一些
//1 5 10
zhangsan.setPriority(Thread.MAX_PRIORITY);
zhangsan.setPriority(Thread.MIN_PRIORITY);
zhangsan.setPriority(Thread.NORM_PRIORITY);
//启动线程
zhangsan.start();
lisi.start();
//但愿主线程最后结束方法一
/* try {
Thread.sleep(1000);//等1000毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}*/
////但愿主线程最后结束方法二:判断子线程是否运行
/* if(zhangsan.isAlive() || lisi.isAlive()){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
////但愿主线程最后结束方法三:让子线程都执行完才能恢复主线程
try {
zhangsan.join();
lisi.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
线程其它方法interrupt()线程中断 :sleep()和join()
**问题:**java线程何时会引起InterruptedException ?
前提:当前线程处于sleep或者join时,被其余线程中断了,那么当前线程会进行异常处理
class ThreadDemo1 implements Runnable{
@Override
public void run() {
for(int i = 1 ; i <=5 ; i++){
System.out.println(Thread.currentThread().getName()+","+i);
if(i == 3){
try {
//Thread.sleep(1000);
Thread.currentThread().join();
} catch (InterruptedException e) {
System.out.println("进入异常处理了");
// e.printStackTrace();
}
}
}
}
}
public class TestThreadInterrupt {
public static void main(String[] args) {
ThreadDemo1 demo1 = new ThreadDemo1();
Thread t1 = new Thread(demo1);
t1.start();
//主线程调用了子线程t1的interrupt方法,子线程t1被中断进入异常处理
t1.interrupt();
}
}
yield() 线程让步 (了解便可,如今基本不用):
Thread.yield():不能彻底保证线程让步
class ThreadDemo1 implements Runnable{
@Override
public void run() {
for(int i = 1 ; i <=5 ; i++){
System.out.println(Thread.currentThread().getName()+","+i);
if(i == 3){
try {
//Thread.sleep(1000);
Thread.currentThread().join();
} catch (InterruptedException e) {
System.out.println("进入异常处理了");
// e.printStackTrace();
}
}
}
}
}
public class TestThreadInterrupt {
public static void main(String[] args) {
ThreadDemo1 demo1 = new ThreadDemo1();
Thread t1 = new Thread(demo1);
t1.start();
//主线程调用了子线程t1的iterrupt方法,子线程t1被中断进入异常处理
t1.interrupt();
}
}
线程的同步什么是同步
某一时刻 此资源 只能被一个线程独占。
线程同步的真实意思和字面意思刚好相反。线程同步的真实意思,实际上是“排队”:几个线程之间要排队,一个一个对共享资源进行操做,而不是同时进行操做。
为何使用同步
当两个或两个以上的线程须要共享资源,他们须要某种方法来肯定资源在某一时刻仅被一个线程占用,达到此目的的过程叫作同步。(某一时刻资源只能被一个线程独占)
使用同步
synchronized(对象){
同步块;
}
同步方法,锁的是对象 this
synchronized 方法{ }
1
/**同步示例代码*/
class Bank implements Runnable{
int money = 0;
//存钱
//同步方法
synchronized public void setMoney(){
money += 100;//存100
System.out.println(Thread.currentThread().getName() + "存了100,余额:" +money);
}
@Override
public void run() {
for(int i = 0 ; i < 3 ; i++){
//同步锁
//同步块
/* synchronized(this){
setMoney();
}*/
setMoney();
}
}
}
public class TestBank {
public static void main(String[] args) {
Bank bank = new Bank();
Thread zhangsan = new Thread(bank,"zhangsan");
Thread lisi = new Thread(bank,"lisi");
zhangsan.start();
lisi.start();
}
}
Lock优点
能够显示加锁,释放锁
得到锁:
当一个线程 访问此对象的 同步块 或 同步方法的时候,
申请同步锁,申请成功了,就得到了锁。在执行 同步块
和 同步方法的过程当中,其它线程 进入 线程锁定池中处于
阻塞状态。只有 当前执行锁的线程 释放了锁 其它线程
才有 机会 得到CPU的调用执行。
释放锁:
1.同步方法或同步块中的 代码正常执行完了,就释放了;
2. 出现了未处理的 异常Exception和
Error时 ,释放锁;
3。 break,return语句,会结束方法或
代码块,那么会释放锁。
4. 执行了 wait()会释放锁。
语法:
try{
加锁lock
}finally{
释放unLock
}
lock做用
能够显示加锁和释放锁
提供了更多功能
死锁
每一个对象只有一个锁(lock)不之相关联
实现同步是要很大的系统开销做为代价的,甚至可 能形成死锁,因此尽可能避免无谓的同步控制
/**死锁示例代码 */
class Zhangsan{
public void say(){
System.out.println("你给我书,我就给你画");
}
public void get(){
System.out.println("张三得到了书");
}
}
class Lisi{
public void say(){
System.out.println("你给我画,我就给你书");
}
public void get(){
System.out.println("李四得到了画");
}
}
class LockDemo implements Runnable{
static Zhangsan zhangsan = new Zhangsan();
static Lisi lisi = new Lisi();
boolean tag ;
@Override
public void run() {
if(tag == true){//张三
synchronized(zhangsan){
zhangsan.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(lisi){
zhangsan.get();
}
}
}else{//李四
synchronized(lisi){
lisi.say();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(zhangsan){
lisi.get();
}
}
}
}
}
public class Testlock {
public static void main(String[] args) {
LockDemo demo1 = new LockDemo();
demo1.tag = true;
LockDemo demo2 = new LockDemo();
demo2.tag = false;
Thread t1 = new Thread(demo1);
Thread t2 = new Thread(demo2);
t1.start();
t2.start();
}
}
wait()和sleep的区别:
区别:
时间参数
wait()能够可定时间也能够丌指定; sleep()必须指定时间;
同步状态
sleep()释放执行权,不释放锁 ;wait释放执行权,释放锁
class Show implements Runnable{
int i = 10 ;
@Override
synchronized public void run() {
for(; i >= 0 ; i--){
if(i == 5 && Thread.currentThread().getName().equals("t1:")){
try {
//Thread.sleep(100000);
wait(1000);
System.out.println("我醒了");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Exercise1 {
public static void main(String[] args) {
Show sh = new Show();
Thread t1 = new Thread(sh,"t1:");
Thread t2 = new Thread(sh,"t2:");
t1.start();
t2.start();
}
}
包子铺实例理解wait()、notify()
package day26;
class QingFeng {
private int count;//包子数量
private boolean tag = false;//true ->有包子,false->没包子
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
//生产包子
synchronized public void put(int count){
//有包子,休息
if(tag == true){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//没有包子 false
this.count = count;
System.out.println("生产了" +this.count);
tag = true;
notify();//唤醒销售
}
//销售包子
synchronized public void get(){
//没包子可卖,休息一会
if(tag == false){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 有包子true
System.out.println("卖了" +this.count);
tag = false;//卖完了
notify();//唤醒厨师
}
}
//生产
class Producer implements Runnable{
QingFeng qingfeng;
public Producer(QingFeng qingfeng) {
super();
this.qingfeng = qingfeng;
}
public Producer() {
super();
}
@Override
public void run() {
//生产
for(int i = 1 ; i <=5 ; i++){
qingfeng.put(i);
}
}
}
//销售
class Consumer implements Runnable{
QingFeng qingfeng;
public Consumer() {
super();
}
public Consumer(QingFeng qingfeng) {
super();
this.qingfeng = qingfeng;
}
@Override
public void run() {
for(int i = 1 ; i <= 5 ; i++){
qingfeng.get();
}
}
}
public class Exercise2 {
public static void main(String[] args) {
QingFeng qingfeng = new QingFeng();
Producer pro = new Producer(qingfeng);
Consumer con = new Consumer(qingfeng) ;
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
t1.start();
t2.start();
}
}