线程的概念:
在一个程序中同时独立运行的多个独立流程,每一个独立流程就是一个线程
线程的三要素:
CPU,Code,Data
进程:完成一个任务的过程
一个进程包括多个线程
线程是计算机执行的最小程序单元
线程并发
线程的开发:继承Thread类与实现Runnable接口2种方式
1.继承Thread类:
public
class
MyThread1
extends
Thread {
public
void
run(){
for
(
int
i=0;i<60;i++){
System.
out
.println(
"####"
+i);
}
}
}
public
class
MyThread2
extends
Thread{
public
void
run(){
for
(
int
i=0;i<60;i++){
System.
out
.println(
"$$$$"
+i);
}
}
}
public class TestThread01 {
public static void main(String[] args) {
Thread t1= new MyThread1();
Thread t2= new MyThread2();
t1.start();
t2.start();
}
}
2.实现Runnable接口:
用户开发一个类实现Ruannable接口
实现run()方法
运行线程
Ruannable target=new MyRunnable2();
Thread t3=new Thread(target);
public class MyThread03 implements Runnable{
public void run() {
for(int i=0;i<400;i++){
System. out.println("****" +i);
}
}
}
public class MyThread04 implements Runnable{
public void run() {
for(int i=0;i<400;i++){
System. out.println("&&&&" +i);
}
}
}
public class TestThread3 {
public static void main(String[] args) {
Runnable runn3=new MyThread03();
Runnable runn4= new MyThread04();
Thread t3= new Thread(runn3);
Thread t4= new Thread(runn4);
t3.start();
t4.start();
}
}
继承Thread是面向对象的编程方式
实现Runnable接口解决了单一继承限制
线程的状态:
初始状态
Thread a=new Thread();
可运行状态
a.start(),但此时未获得CPU或者可运行状态CPU时间片到期
运行状态
可运行状态获得CPU
终结状态
run()方法退出
sleep()方法
public static void sleep(long millis) throws InterruptedException
public
class
MyThread1
extends
Thread {
public
void
run(){
for
(
int
i=0;i<10;i++){
System.
out
.println(
"####"
+i);
try
{
Thread. sleep(200);
}
catch
(InterruptedException e) {
}
}
}
}
public class MyThread2 extends Thread{
public void run(){
for(int i=0;i<10;i++){
System. out.println("$$$$" +i);
try {
Thread. sleep(200);
} catch (InterruptedException e) {
}
}
}
}
public class TestThread01 {
public static void main(String[] args) {
Thread t1= new MyThread1();
Thread t2= new MyThread2();
t1.start();
t2.start();
}
}
运行结果:
$$$$0
####0
####1
$$$$1
$$$$2
####2
$$$$3
####3
####4
$$$$4
$$$$5
####5
$$$$6
####6
####7
$$$$7
####8
$$$$8
$$$$9
####9
join()方法:
join()方法也会导致线程的阻塞
特点:如果当前线程中调用了另外一个线程join方法,
join()方法的问题:
如果两个线程彼此调用对方的join方法,会导致程序无法运行
解决方法如下:
public final void join(long millis) throws InterruptedException
public class MyThread2 extends Thread{
Thread t;
public void run(){
for(int i=0;i<100;i++){
System. out.println("$$$$" +i);
try {
t.join(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
线程同步:
多个线程并发访问同一个对象,如果破坏了不可分割的操作,从而就会造成数据不一致。
临界资源:多个线程并发访问同一个对象
原子操作:不可分割的操作
被多线程并发访问时,如果一个对象有可能出现数据不一致的问题,那么这个对象就称为线程不安全的对象
如何解决多线程并发访问的问题
synchronized(object){
}
或者写成synchronized(this){}
synchronized修饰方法
public synchronized void push(){}
死锁:
用于解决死锁的方法:wait()与notify()方法(这两种方法也可进行线程间的通信)
生产者与消费者问题:
同时两个线程操作一个栈,一个线程负责往栈中添加元素,一个线程负责删除栈中元素。
5.生产者与消费者问题
1.创建临界资源(Stack) push(),pop(),print()
2.给push()与pop()方法加上线程同步
3.定义一个线程类,实现往Stack对象中存放那个相应数据,在线程中初始化临界资源(Stack)
4.定义一个线程类,实现从Stack中取出相应数据,在线程中初始化临界资源(Stack)
5.写一个测试类,启动3,4中创建的线程
6.运行5中的测试类进行测试,发现出现异常,分析异常,解决异常
异常原因:存数据时,字符数组大小固定导致异常
取数据时,字符数组下标越界导致异常
7.解决异常:在一中创建的临界资源(Stack)中的push()方法中加入判断,如果当前下标值==数组长度,则不能继续存入数据,此时,通过线程的wait()方法,通知消费者从临界资源读取数据;
在一中创建的临界资源(Stack)中的pop()方法中加入判断,如果当前下标值==0,则不能继续取出数据,此时,通过线程的notify()方法,通知生产者向临界资源中存入数据
当生产者往临界资源中存入数据时,需要通知消费者从临界资源中读取数据;
当消费者从临界资源中取出数据时,需要通知生产者向临界资源中存入数据;
1.创建临界资源(Stack) push(),pop(),print()
2.给push()与pop()方法加上线程同步
3.定义一个线程类,实现往Stack对象中存放那个相应数据,在线程中初始化临界资源(Stack)
4.定义一个线程类,实现从Stack中取出相应数据,在线程中初始化临界资源(Stack)
5.写一个测试类,启动3,4中创建的线程
6.运行5中的测试类进行测试,发现出现异常,分析异常,解决异常
异常原因:存数据时,字符数组大小固定导致异常
取数据时,字符数组下标越界导致异常
7.解决异常:在一中创建的临界资源(Stack)中的push()方法中加入判断,如果当前下标值==数组长度,则不能继续存入数据,此时,通过线程的wait()方法,通知消费者从临界资源读取数据;
在一中创建的临界资源(Stack)中的pop()方法中加入判断,如果当前下标值==0,则不能继续取出数据,此时,通过线程的notify()方法,通知生产者向临界资源中存入数据
当生产者往临界资源中存入数据时,需要通知消费者从临界资源中读取数据;
当消费者从临界资源中取出数据时,需要通知生产者向临界资源中存入数据;
//临界资源
public class ProducerStack {
private char[] data=new char[12];
private int index=0;
public synchronized void push(char ch){
while(data.length==index){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
data[index]=ch;
/* try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
index++;
this.notify();
System.out.println(ch+" push Stack:");
}
public synchronized void pop(String s){
System.out.println(s);
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
index--;
this.notify();
System.out.println(data[index]+" pop Stack");
data[index]=' ';
}
public void print(String s){
System.out.println(s);
for(int i=0;i System.out.print(data[i]);
}
System.out.println();
}
private char[] data=new char[12];
private int index=0;
public synchronized void push(char ch){
while(data.length==index){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
data[index]=ch;
/* try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
index++;
this.notify();
System.out.println(ch+" push Stack:");
}
public synchronized void pop(String s){
System.out.println(s);
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
index--;
this.notify();
System.out.println(data[index]+" pop Stack");
data[index]=' ';
}
public void print(String s){
System.out.println(s);
for(int i=0;i
}
System.out.println();
}
}
//消费者
public class Consumer extends Thread {
ProducerStack ps;
public Consumer(ProducerStack ps) {
this.ps=ps;
}
public void run() {
ps.pop("pop01-----");
ps.print("pop-------");
}
}
//生产者
public class Producer extends Thread {
ProducerStack ps;
public Producer(ProducerStack ps) {
this.ps=ps;
}
public void run() {
for(int i=0;i<20;i++){
ps.push('s');
}
ps.print("push----");
}
}
//测试类
public class TestProducer {
public static void main(String[] args) {
ProducerStack ps=new ProducerStack();
Thread p=new Producer(ps);
Thread con=new Consumer(ps);
p.start();
con.start();
}
}