进程: 进程就是计算机的运行线索
线程: 进程的运行线索,计算机运行的最小单位
java中如何创建一个线程
1,1 以实现了Runable 接口的类的实例作为创建
Thread类的对象的构造函数的参数。
第一种创建线程方式
package corelesson5;
import corelesson4.A;
public class ThreadDemo1 {
public static void main(String[] args) {
//创建线程,就要以实现runable 接口的类的对象 作为创建 Thread 对象的构造函数的参数
A a =new A();
Thread t1 = new Thread(a);// 以对象作为参数,现在线程对象创建出来了
t1.start();// 启动线程
// r如果直接调用run 方法 就不是线程做的事了 必须用线程对象去调用
// 主函数本身是一个线程 我们称为主线程
for(;;){
System.out.println("world");
}
}
}
class A implements Runnable{
@Override
public void run() {// 就是线程要执行的任务
for(;;){
System.out.println("hello");
}
}
}
1,2创建线程方式2
直接创建类继承Thread 重写run 方法
package corelesson5;
public class ThreadDemo2 {
public static void main(String[] args) {
// 方式2 这里创建了MyThread 的对象 就是创建了线程对象
MyThread t1 = new MyThread();
t1.start();// 启动线程
for(;;){
System.out.println("world");
}
}
}
class MyThread extends Thread{
@Override
public void run() {
super.run();
for (;;){
System.out.println("hello");
}
}
}
两种方式都可以 建议使用第一种方式
因为 一个Runable 的实例我们就可以认为是一个任务
1.3 直接使用匿名类方式创建线程
package corelesson5;
public class ThreadDemo3 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (;;){
System.out.println("hello");
}
}
}).start();
//内部类
new Thread(){
public void run(){
for(;;){
System.out.println("world");
}
}
}.start();
}
}
知识点1, 多线程的程序经常每次运行结果可能不一样
Runnable(Running/Ready) 跟这个状态有关系
线程顺序,
1,先来后到
2,优先级优先(拿到锁之后 优先级减一)
3,时间片轮换
2,java线程的生命周期newBron新生状态
Pause 阻塞状态
Runable 可执行状态(Running ,Ready两种状态)
Dead (不是stop--------->死是不能复生的 )
3,java线程中常用方法package corelesson5;
public class ThreadDemo4 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
System.out.println(t1.getName());// 获取线程的名字
t1.setName("线程1"); // 修改线程的名字
System.out.println(t1.getName());
// 获取当前线程的名字
System.out.println(Thread.currentThread().getName());
// 获取线程优先级的等级,如果线程没有设置优先级,默认是5级
System.out.println(t1.getPriority());
// 优先级的范围 , 最大的是10 ,最小的是1,一般的是5,
System.out.println(Thread.MAX_PRIORITY);
System.out.println(Thread.MIN_PRIORITY);
System.out.println(Thread.NORM_PRIORITY);
}
}
3.2 重要的一些方法
Thread.sleep(),让线程睡,线程进入阻塞状态,不会参与竞争
package corelesson5;
public class ThreadDemo5 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("线程中断");
}
System.out.println("helloworld");
}
});
t1.start();
for (int i = 0; i <10 ; i++) {
try {
t1.sleep(10000);// 主线程sleep 10秒、、相当于Thread.sleep(10000)
// 那个线程执行到sleep 方法 ,那个线程就去sleep
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
t1.interrupt();// 让睡眠中断 执行完以上任务之后 就唤醒线程
}
}
interrupt 方法中断线程的睡眠,相当于唤醒
join() 方法 一个线程等待另一个线程运行结束
package corelesson5;
public class ThreadDemo7 {
public static void main(String[] args) {
MyThread2 thread2=new MyThread2();
thread2.start();
try {
thread2.join();//主线程等待thread2 线程运行结束之后才运行
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i <10 ; i++) {
System.out.println("hello");
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for (int i = 0; i <=10 ; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
Thread.yield() 主动放弃CPU把机会放给别的线程,然后参与竞争 Running-----ready
4,ThreadLocal 类的使用 5,java线程互斥机制---多线程之间共享数据问题
5.1 同步块
保证每一段代码同时只能被一个线程访问
关键字
synchronized(对象){}
java中每一个对象都是一把锁有且只有一把钥匙
出同步块就会释放锁的钥匙。
package corelesson5;
public class ThreadDemo9 {
public static void main(String[] args) {
Date date =new Date();
//数据共享的问题
Thread t1= new Thread(date);
Thread t2= new Thread(date);
t1.start();
t2.start();
}
}
class Date implements Runnable{
private int i;
@Override
public void run() {
int h;
for (int j = 0; j <10 ; j++) {
synchronized (this){
h=i+1;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i=h;
}
System.out.println(i);
}
}
}
package corelesson5;
public class ThreadDemo10 {
public static void main(String[] args) {
Date date =new Date();
//数据共享的问题
Thread t1= new Thread(date);
Thread t2= new Thread(date);
t1.start();
t2.start();
}
}
class Date1 implements Runnable{
private int i;
@Override
public synchronized void run() {
int h;
for (int j = 0; j <10 ; j++) {
h=i+1;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i=h;
System.out.println(i);
}
}
}
5.2 同步函数 也是有锁存在的
--普通方法的锁就是 当前对象
在任何方法 前面都可以加关键字synchronized
静态函数同步块也是有锁的---》 锁是当前类的类类型
注意:多个线程共享数据要保证是同一把锁。
注意:死锁的问题 死锁程序就卡死,无法调试----》可以通过好的工具来检查死锁的问题。
两个线程相互等待对方释放锁。
要慎用synchronized 关键字。
注意:之前我们讲 stringbufferder 和stringbuilder
还有集合ArrayList / Vecter(有关键字synchronized)
5.3 synchronized很繁琐 比较不要理解而且不面向对象
java5 版本做了很好的改进 有了Lock 对象。
大多数情况下用语句。
Lock l=。。。
l.lock().
try{
//程序。。。。。
}finally{
l.unlock().
}
Lock 对象package corelesson5;
import com.sun.org.apache.xpath.internal.operations.Variable;
import javax.lang.model.element.VariableElement;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo12 {
public static void main(String[] args) {
final Output1 output = new Output1();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
output.print("hello");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
output.print("world");
}
}
}).start();
}
}
class Output1{
//穿建了锁对象
Lock lock= new ReentrantLock();
public void print(String name){
lock.lock();
try {
for (int i = 0; i
扩展内容 线程并发下的缓存
package corelesson5;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDemo {
HashMaphm=new HashMap();
private ReentrantReadWriteLock rrw=new ReentrantReadWriteLock();
private java.lang.String value=null;
public java.lang.String fetDate(String key){
rrw.readLock().lock();//进来之后先读数据
try {
value=hm.get(key);// 大家都可以来读这个数据
if(value==null){
// 要进行写操作
rrw.readLock().unlock();
rrw.writeLock().lock();
try{if(value==null) {
value = "hello";
hm.put(key, value);
}
}finally {
rrw.writeLock().unlock();
rrw.readLock().lock();
}
}
}finally {
rrw.readLock().unlock();
}
return value;
}
}
6,java线程通讯机制
6.1通过管道流的方式进行通讯
package corelesson5;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class ThreadDemo13 {
public static void main(String[] args) {
PipedOutputStream out=null;
PipedInputStream in=null;
try {
in=new PipedInputStream();
out=new PipedOutputStream(in);
} catch (Exception e) {
e.printStackTrace();
}
Sender sender =new Sender(out);
Thread t1= new Thread(sender);
Receiver receiver = new Receiver(in);
Thread t2= new Thread(receiver);
t1.start();
t2.start();
}
}
class Sender implements Runnable{
private OutputStream out;
public Sender(OutputStream out) {
this.out = out;
}
@Override
public void run() {
for (int i = 0; i <5 ; i++) {
byte value =(byte)(Math.random()*100);
System.out.println("send the value is :"+value);
try {
out.write(value);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Receiver implements Runnable{
private InputStream in;
public Receiver(InputStream in) {
this.in = in;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
byte value=(byte)in.read();
System.out.println("receiver the value is "+value);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通过 管道进行简单的通讯,(性能较差)
6.2 通过 Thread.yield() 方式
yield(一直放弃cpu资源等待)
模拟生产者 和消费者的模型
package corelesson5;
import java.util.Random;
public class ThreadDemo14 {
public static void main(String[] args) {
FlagSend flagSend = new FlagSend();
FlagRec flagRec = new FlagRec(flagSend);
Thread t1=new Thread(flagSend);
Thread t2=new Thread(flagRec);
t1.start();
t2.start();
}
}
class FlagSend implements Runnable{
int thevalue;
boolean flag;
@Override
public void run() {
for (int i = 0; i <5 ; i++) {
while (flag){
Thread.yield();
}
thevalue= new Random().nextInt(1000);// 制造食物
System.out.println("send the value is :"+ thevalue);
// 自己去等待 让食客去吃
flag=true;
}
}
}
class FlagRec implements Runnable{
private FlagSend flagSend;
public FlagRec(FlagSend flagSend) {
this.flagSend = flagSend;
}
@Override
public void run() {
for (int i = 0; i <5 ; i++) {
while (!flagSend.flag){
Thread.yield();
}
System.out.println("receiver the value is :"+flagSend.thevalue);
flagSend.flag=false;
}
}
}
效率也比较差 。yield 是放弃了cup 然后又去死循环的竞争 放弃,给CPU 会造成很大的压力。
6.3线程间通讯 wait/notify 方式来通讯 ,等待 和唤醒其他线程。
概念: 任何一个对象 都拥有一个线程等待池,挂在同一个对象的线程等待池中的线程之间可以互相唤醒。
所以 wait/notify 方法是属于object 类的。
wait 方法的使用必须放在synchronized 同步块中。
package corelesson5;
import java.util.Random;
public class ThreadDemo15 {
public static void main(String[] args) {
WaitSeed send = new WaitSeed();
waitRec rec = new waitRec(send);
Thread t1 = new Thread(send);
Thread t2 = new Thread(rec);
// 把t2 线程设置为守护线程,当只有守护线程运行的时候程序自动结束
t2.setDaemon(true);
t1.start();
t2.start();
}
}
class WaitSeed implements Runnable{
boolean flag;
int thevalue;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
synchronized (this){
while (flag){
// 为什么 需要用while 存在中断和虚假唤醒
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产者生产食物
thevalue= new Random().nextInt(1000);
System.out.println("send the value is:"+thevalue);
// 自己去等待
flag= true;
//唤醒消费者
this.notify();
}
}
}
}
class waitRec implements Runnable{
// 把生产者作为你的成员
private WaitSeed send;
public waitRec(WaitSeed send) {
this.send = send;
}
@Override
public void run() {
// 不知道生产者生产多少食物,生产多少消费多少
while(true)
{
synchronized (this){
while (!send.flag){
try {
send.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 不等待的话 就消费食物
System.out.println( "receiver the value is :"+send.thevalue);
send.flag=false;
send.notify();
}
}
}
}
面试题:
先A线程运行10次, 然后B线程运行20次
如此反复50次
理解:A线程生产者, 生产食物需要循环10次,
B线程是消费者 消费食物循环20 次,
package corelesson5;
public class ThreadDemo18 {
public static void main(String[] args) {
final Business1 bus = new Business1();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
bus.a();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
bus.b();
}
}
}).start();
}
}
class Business1{
boolean flag;
public void a(){
synchronized (this){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 10; i++) {
System.out.println("A线程循环"+i);
}
flag=true;
this.notify();
}
}
public void b(){
// B是消费者
synchronized (this){
while(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//循环20次
for (int i = 0; i < 20; i++) {
System.out.println("B 线程循环"+i);
}
flag=false;
this.notify();
}
}
}
6.4 java 中引入了新的线程通讯方式(了解)
用的是锁机制
7,线程范围内数据共享
模拟一个缓存map ,每次都从map 中取,没有就往里面放数据。
HashMap key,就是当前线程的对象 value 就是你要的数据,不管经过那个模块 就可以先去map 中取。
Thread.currentThread() 获取当前线程对象
package corelesson5;
import java.util.HashMap;
import java.util.Random;
public class ThreadDemo20 {
private static HashMap data = new HashMap<>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int value= new Random().nextInt(10000);
data.put(Thread.currentThread(),value);
A a = new A();
a.getDate();
B b = new B();
b.getDate();
C c = new C();
c.getDate();
}
}).start();
}
}
static class A{
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from A get data is:"+value);
}
}
static class B {
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from B get data is:"+value);
}
}
static class C{
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from C get data is:"+value);
}
}
}
java 中 提供了ThreadLocal 这个类,已经完成了类似的功能,可以直接使用。
package corelesson5;
import java.util.HashMap;
import java.util.Random;
public class ThreadDemo20 {
private static HashMap data = new HashMap<>();
private static ThreadLocal tl=new ThreadLocal<>();
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int value= new Random().nextInt(10000);
data.put(Thread.currentThread(),value);
tl.set(value);
System.out.println("put to "+Thread.currentThread().getName() +"is:"+ value +" set tl value is:"+value);
A a = new A();
a.getDate();
B b = new B();
b.getDate();
C c = new C();
c.getDate();
}
}).start();
}
}
static class A{
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from A get data is:"+value +".........threadlocal is:"+tl.get());
}
}
static class B {
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from B get data is:"+value+".........threadlocal is:"+tl.get());
}
}
static class C{
public void getDate(){
Thread t =Thread.currentThread();
int value =data.get(t);
System.out.println(t.getName()+" from C get data is:"+value+".........threadlocal is:"+tl.get());
}
}
}
主要 用两个方法 tl.set() 放数据 tl.get() 取数据 tl.remove(); 删除。
7.3 写一个类,使得该类砸创建对象时,创建完成之后直接就是同一个线程,同一个对象,不同线程,对象不同。
package corelesson5;
class ThreadDemo21{
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
UserService us=UserService.getInstance();
A a = new A();
B b = new B();
a.print();
b.print();
}
}).start();
}
}
static class A{
public void print(){
System.out.println("from A==="+Thread.currentThread().getName());
UserService us =UserService.getInstance();
System.out.println("from A==="+Thread.currentThread().getName()+"..A..."+us);
}
}
static class B{
public void print(){
System.out.println("from B==="+Thread.currentThread().getName());
UserService us =UserService.getInstance();
System.out.println("from B==="+Thread.currentThread().getName()+"..B..."+us);
}
}
}
public class UserService {
private static ThreadLocal tl=new ThreadLocal<>();
private UserService(){}// 线程私有 ,不然别人一new 就是一个对象
public static UserService getInstance(){
UserService us=tl.get();
if(us==null){
us= new UserService();
tl.set(us);
}
return us;
}// 构造函数私有的时候 我们就需要通过静态的方法来返回类的对象。
}
不管是单例模式 还是这种情况,我们都是的构造函数peivate
package corelesson5;
import java.lang.reflect.Constructor;
class ThreadDemo21{
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
UserService us=UserService.getInstance();
A a = new A();
B b = new B();
a.print();
b.print();
}
}).start();
}
System.out.println("===================================");
Class c= UserService.class;
try {
Constructorcs=c.getDeclaredConstructor(new Class[]{});// 获得自己声明的构造函数
cs.setAccessible(true);//private 设置访问方式
UserService us1=cs.newInstance(new Object[]{});
UserService us2=cs.newInstance(new Object[]{});
System.out.println(us1=us2);// 看看是不是同一个
} catch (Exception e) {
e.printStackTrace();
}
}
static class A{
public void print(){
System.out.println("from A==="+Thread.currentThread().getName());
UserService us =UserService.getInstance();
System.out.println("from A==="+Thread.currentThread().getName()+"..A..."+us);
}
}
static class B{
public void print(){
System.out.println("from B==="+Thread.currentThread().getName());
UserService us =UserService.getInstance();
System.out.println("from B==="+Thread.currentThread().getName()+"..B..."+us);
}
}
}
public class UserService {
private static ThreadLocal tl=new ThreadLocal<>();
private UserService(){}// 线程私有 ,不然别人一new 就是一个对象
public static UserService getInstance(){
UserService us=tl.get();
if(us==null){
us= new UserService();
tl.set(us);
}
return us;
}// 构造函数私有的时候 我们就需要通过静态的方法来返回类的对象。
}
8,java线程池
线程并不是越多越好,如果无限制的穿建线程, 那么线程的创建和销毁都有很大的消耗,
希望 不管执行多少任务,都用固定的线程数来执行
package corelesson5;
public class ThreadDemo22 {
public static void main(String[] args) {
for (int i = 1; i <=10; i++) {
final int task=i;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("任务"+task);
}
}).start();
}
}
}
线程池也是java5 之后引入的
如何创建线程池?
Executors 类
newFixedThreadPool() 穿建固定线程数的线程池
newSingleThreadExecutor();// 创建了单一线程,线程只有一个线程。
newCachedThreadPool();//默认创建线程,这些线程会被缓存起来,自动判断要不要创建新的线程
package corelesson5;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadDemo23 {
public static void main(String[] args) {
// 创建一个线程池,下面是3个线程并发处理了10 个任务
ExecutorService threadPool= Executors.newFixedThreadPool(3);// 创建3个固定的线程
for (int i = 0; i < 10; i++) {// 创建了10个runnable 的实例 都是用同一个线程池的对象threadPool 来执行的
final int task=i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10; j++) {
// 每个任务循环10次。
System.out.println(Thread.currentThread().getName()+"执行第"+task+"个任务的第:"+j+"次循环");
}
}
});
}
threadPool.shutdown(); // 关闭线程池
}
}
穿建线程池方式二
newCachedThreadPool();//默认创建线程,这些线程会被缓存起来,自动判断要不要创建新的线程
newSingleThreadExecutor();// 创建了单一线程,线程只有一个线程。
newFixedThreadPool() 穿建固定线程数的线程池
newScheduledThreadPool(1)
package corelesson5;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadDemo23 {
public static void main(String[] args) {
// 创建一个线程池,下面是3个线程并发处理了10 个任务
// ExecutorService threadPool= Executors.newFixedThreadPool(3);// 创建3个固定的线程
// ExecutorService threadPool=Executors.newSingleThreadExecutor();// 创建了单一线程,线程只有一个线程。
ExecutorService threadPool=Executors.newCachedThreadPool();//默认创建线程,这些线程会被缓存起来,自动判断要不要创建新的线程
for (int i = 0; i < 10; i++) {// 创建了10个runnable 的实例 都是用同一个线程池的对象threadPool 来执行的
final int task=i;
threadPool.execute(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10; j++) {
// 每个任务循环10次。
System.out.println(Thread.currentThread().getName()+"执行第"+task+"个任务的第:"+j+"次循环");
}
}
});
}
threadPool.shutdown(); // 关闭线程池
}
}
package corelesson5;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadDemo24 {
public static void main(String[] args) {
ScheduledExecutorService threadPool= Executors.newScheduledThreadPool(1);
threadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(" 爆炸了。。。。");
}
},0,2, TimeUnit.SECONDS);
}
}
8,Callable
Callable 有返回值,
package corelesson5;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadDemo25 {
public static void main(String[] args) {
ExecutorService threadPool= Executors.newSingleThreadExecutor();
//Callable 泛型的具体类型就是返回值的类型 也决定了 Future 泛型的类型
Future future = threadPool.submit(new Callable() {
@Override
public Integer call() throws Exception {
System.out.println("线程任务开始。。。。");
Thread.sleep(3000);
System.out.println("线程任务结束。。。。");
return 10;
}
});
try {
int value= future.get();// 取返回值
System.out.println(value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
关于线程基础内容 就先了解这么多。



