程序:完成特定任务,由某种语言编写的代码。是一段静态代码。
进程:在内存中运行的一个应用程序
线程:进程执行的某一条路径
进程和线程的根本区别:进程是操作系统分配资源的基本单位,线程是处理器任务调度和执行的基本单元
一、Java中实现线程的四种方式:1.继承Thread类
步骤:
①继承Thread类
②重写run方法
③声明子类对象
④调用start()方法
public class ThreadTset {
public static void main(String[] args) {
MyThread thread=new MyThread();
thread.start();
}
}
class MyThread extends Thread{
public void run() {
// 1-100的偶数
for(int i=1;i<=100;i++) {
if(i % 2 ==0) {
System.out.println(i);
}
}
}
}
2.实现Runnable接口
步骤:
1.实现Runnbale接口
2.重写run方法
3.声明实现类对象
4.实现类对象作为Thread类构造器的参数,声明Thread类对象
5.Thread类对象调用start()方法
public class ThreadTset {
public static void main(String[] args) {
UThread uthread =new UThread();
Thread t1=new Thread(uthread);
t1.start();
}
}
class UThread implements Runnable{
public void run() {
// 1-100的奇数
for(int i=1;i<=100;i++) {
if(i % 2 != 0) {
System.out.println(i);
}
}
}
}
3.实现Callable接口
步骤:
①实现Callable接口
②重写call()方法
③声明实现类对象
④实现类对象作为FutureTask类构造器的参数,声明FutureTask类对象
⑤FutureTask类的对象又作为Thread类构造器的参数,声明Thread的对象
⑥调用start()方法
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTset {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyThread thread=new MyThread();
FutureTask task=new FutureTask(thread);
Thread t1=new Thread(task);
t1.start();
System.out.println("sum + ="+task.get());
}
}
class MyThread implements Callable{
public Object call() {
// 1-20偶数的和
int sum=0;
for(int i=1;i<=20;i++) {
if(i % 2 == 0) {
sum+=i;
System.out.println(Thread.currentThread().getName()+"->"+i);
}
}
return sum;
}
}
Callable接口与Runnable接口对比:
1.Callable接口支持泛型
2.call方法有返回值,可以抛出异常
public class ThreadTset {
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyThread thread=new MyThread();
FutureTask task=new FutureTask(thread);
Thread t1=new Thread(task);
t1.start();
System.out.println("sum + ="+task.get());
}
}
class MyThread implements Callable{
public Integer call() throws Exception {
// 1-20偶数的和
int sum=0;
for(int i=1;i<=20;i++) {
if(i % 2 == 0) {
sum+=i;
System.out.println(Thread.currentThread().getName()+"->"+i);
}
}
return sum;
}
}
FutureTask中的get()方法返回call()方法的返回值
4.线程池:
使用线程池的好处:
①提高效率
②节省资源
③便于管理
Executors是一个工具类,作用:创建一个线程池
public class ThreadTset {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService cacheThreadPool=Executors.newCachedThreadPool();
cacheThreadPool.execute(new Thread() {
public void run() {
for(int i=1;i<=20;i++) {
if(i % 2==0) {
System.out.println(i);
}
}
}
});
cacheThreadPool.shutdown();
}
}
二、Thread类中的常用方法
1.currentThread():返回当前正在执行线程的对象
2.start():启动一个线程,执行run方法
3.run():让子类覆盖次方法,线程的任务
4.sleep(long time):让线程睡眠time毫秒
5.setName():设置线程的名字
6.getName():获取线程的名字
7.join():等待执行该方法的线程结束
8.yield():释放出cpu的执行权
9.stop():让线程结束
三、线程的声明周期 四、synchronized关键字
class Window extends Thread{
private static int ticket=100;
public void run() {
while(true) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出:"+ticket+"号票");
ticket--;
}else {
break;
}
}
}
}
public class ThreadTset {
public static void main(String[] args) {
Window w1=new Window();
w1.setName("窗口1");
Window w2=new Window();
w2.setName("窗口2");
Window w3=new Window();
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
出现的问题:①同票 ②错票
出现问题的原因:
窗口1、窗口2、窗口3同时对共享数据进行了操作
synchronized:
①修饰代码块
synchronized(同步监视器){
// 同步监视器 : 任何一个类的对象都能充当同步监视器,相当于锁
//多个对象需公用一把锁
//类也是对象,且是唯一的
}
class Window extends Thread{
private static int ticket=100;
public void run() {
while(true) {
synchronized(Window.class) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出:"+ticket+"号票");
ticket--;
}
}else {
break;
}
}
}
}
public class ThreadTset {
public static void main(String[] args) {
Window w1=new Window();
w1.setName("窗口1");
Window w2=new Window();
w2.setName("窗口2");
Window w3=new Window();
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
②修饰方法
class Window extends Thread{
private static int ticket=100;
public synchronized void run() {
while(true) {
// synchronized(Window.class) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出:"+ticket+"号票");
ticket--;
}
}else {
break;
}
// }
}
}
public class ThreadTset {
public static void main(String[] args) {
Window w1=new Window();
w1.setName("窗口1");
Window w2=new Window();
w2.setName("窗口2");
Window w3=new Window();
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
原因是: synchronized修饰方法,谁调用次方法谁就充当锁,一个对象一把锁。相当于synchronized(this){}
class Window1 implements Runnable{
private int ticket=100;
@Override
public synchronized void run() {
// TODO 自动生成的方法存根
while(true) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出:"+ticket+"号票");
ticket--;
}else {
break;
}
}
}
}
public class ThreadTset {
public static void main(String[] args) {
Window1 w1=new Window1();
Thread t1=new Thread(w1);
Thread t2=new Thread(w1);
Thread t3=new Thread(w1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window1 implements Runnable{
private int ticket=100;
@Override
public void run() {
synchronized(this) {
while(true) {
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出:"+ticket+"号票");
ticket--;
}else {
break;
}
}
}
// TODO 自动生成的方法存根
}
}
public class ThreadTset {
public static void main(String[] args) {
Window1 w1=new Window1();
Thread t1=new Thread(w1);
Thread t2=new Thread(w1);
Thread t3=new Thread(w1);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
五、ReentrantLock
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTset {
public static void main(String[] args) {
Window w1=new Window();
w1.setName("w1");
Window w2=new Window();
w2.setName("w2");
Window w3=new Window();
w3.setName("w3");
w1.start();
w2.start();
w3.start();
}
}
class SingleTon{
private SingleTon() {
}
private static ReentrantLock instance=new ReentrantLock();
public static ReentrantLock getInstance() {
return instance;
}
}
class Window extends Thread{
private static int ticket=100;
ReentrantLock lock;
{
lock=SingleTon.getInstance();
}
public void run() {
while(true) {
try {
lock.lock();
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"->"+ticket);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
ticket--;
}
}catch(Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
六、线程死锁问题
什么是死锁:我等待你释放资源,你等带我释放资源,彼此陷入了死循环中。
public class ThreadTset {
public static void main(String[] args) {
StringBuffer b1=new StringBuffer();
StringBuffer b2=new StringBuffer();
new Thread() {
public void run() {
synchronized(b1) {
b1.append("a");
b2.append(1);
synchronized(b2) {
b2.append("b");
b2.append(2);
System.out.println(b1);
System.out.println(b2);
}
}
}
};
new Thread() {
public void run() {
synchronized(b2) {
b1.append("b");
b2.append(3);
synchronized(b1) {
b1.append("d");
b2.append(4);
System.out.println(b1);
System.out.println(b2);
}
}
}
};
}
}
七、线程通信
public class ThreadTset {
public static void main(String[] args) {
Data data=new Data();
Thread1 t1=new Thread1(data);
t1.setName("t1");
Thread2 t2=new Thread2(data);
t2.setName("t2");
t1.start();
t2.start();
}
}
class Data{
private int count=1;
public int getCount() {
return count;
}
public synchronized void method1() {
// TODO 自动生成的方法存根
if(count<=100) {
notify();
System.out.println(Thread.currentThread().getName()+"->"+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
count++;
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
public synchronized void method2() {
// TODO 自动生成的方法存根
if(count<=100) {
notify();
System.out.println(Thread.currentThread().getName()+"->"+count);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
count++;
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
class Thread1 extends Thread{
Data data;
public Thread1(Data data) {
this.data=data;
}
public void run() {
while(true) {
data.method1();
if(data.getCount()>100)
break;
}
}
}
class Thread2 extends Thread{
Data data;
public Thread2(Data data) {
this.data=data;
}
public void run() {
while(true) {
data.method2();
if(data.getCount()>100)
break;
}
}
}
线程通信之生产者消费者问题:
public class ThreadTset {
public static void main(String[] args) {
Clerk c=new Clerk();
Producer producer=new Producer(c);
Consume consume=new Consume(c);
producer.setName("producer");
consume.setName("consume");
producer.start();
consume.start();
}
}
class Clerk{
private int product=0;
public int getProduct() {
return product;
}
public synchronized void productItem() {
// TODO 自动生成的方法存根
if(product<20) {
product++;
System.out.println(Thread.currentThread().getName()+"生產第"+product+"號產品");
notify();
}else {
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
public synchronized void consumeItem() {
// TODO 自动生成的方法存根
if(product>0) {
System.out.println(Thread.currentThread().getName()+"消費第"+product+"號產品");
product--;
notify();
}else
{
try {
wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
class Producer extends Thread{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk=clerk;
}
public void run() {
while(true) {
clerk.productItem();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
class Consume extends Thread{
private Clerk clerk;
public Consume(Clerk clerk) {
this.clerk=clerk;
}
public void run() {
while(true) {
clerk.consumeItem();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
sleep与wait方法的比较:
①两者都是让线程阻塞
②sleep方法是Thread类中的静态方法,调用sleep方法并不释放锁
③wait方法是Object类中的方法,必须使用在synchronized修饰的方法或者代码块中,调用wait方法会释放锁



