[Java多线程]线程创建的三种方式,线程的互斥,线程的同步
Posted huamanggg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java多线程]线程创建的三种方式,线程的互斥,线程的同步相关的知识,希望对你有一定的参考价值。
前言
多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
并行和并发:
- 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
- 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
线程创建
最基础的主要分为两种方法
- 继承Thread类
- 实现Runnable接口
创建Thread类的子类
用这种方法生成新线程,可以按以下步骤进行:
- 定义Thread类的子类
class MyThread extends Thread
- 在子类中重写run方法
- 实例化MyThread,调用start方法开始运行
实例:
public class test1
public static void main(String[] argv)
testThread t1 = new testThread();
t1.start();
while(true)
try
Thread.sleep(1);
catch (InterruptedException e)
e.printStackTrace();
System.out.println("Thread 2");
class testThread extends Thread
public void run()
while(true)
try
sleep(1);
catch (Exception e)
System.out.println(e.getMessage());
System.out.println("Thread 1");
实现Runnable接口
- 定义一个类MyThread实现Runnable接口
- 实现他的唯一的抽象函数run()
- 实例化MyThead
- 再实例化Thread(MyThread,name)
- 调用start方法
// 用runnable构造线程
public class Book2
public static void main(String[] argv)
System.out.println("开始");
MyThread2 m1,m2,m3;
Thread t1,t2,t3;
m1 = new MyThread2(2,70);
m2 = new MyThread2(3,70);
m3 = new MyThread2(5,70);
t1 = new Thread(m1,"A");
t2 = new Thread(m2,"B");
t3 = new Thread(m3,"C");
t1.start();
t2.start();
t3.start();
System.out.println("当前共有"+Thread.activeCount()+"个线程");
System.out.println("Main结束");
class MyThread2 implements Runnable
private int n,max;
public MyThread2(int n1,int max1)
n = n1;
max = max1;
@Override
public void run()
int i = 1;
while(n*i<=max)
System.out.println(n*i+" ");
i++;
System.out.println(Thread.currentThread().getName()+"结束");
其他构造线程的方式
这里还有一个更加灵活的方式去实现线程的构造
主要是思路就是在实现Runnable的时候,在析构方法中就创建Thread的对象,再添加一个start方法
这样在mian方法里面,就可以直接实例化MyThread,直接调用start方法,不需要像第二个方法一样再去创建一个Thread对象
- 创建MyThread类实现Runnable接口
- 在析构方法中实例化Thread对象
- 创建start方法
- 在mian中实例化MyThread,直接调用MyThread类的start开启线程
实例:
public class test2
public static void main(String[] argv)
System.out.println("开始");
MyThread2 m1,m2;
m1 = new MyThread2(1,"第一个");
m2 = new MyThread2(3,"第二个");
m1.start();
m2.start();
System.out.println("当前共有"+Thread.activeCount()+"个线程");
System.out.println("Main结束");
class MyThread2 implements Runnable
private int n;
private Thread t;
public MyThread2(int n1,String name)
n = n1;
t = new Thread(this,name);
//这里不是对Thread类的start方法的重写
public void start()
t.start();
@Override
public void run()
System.out.println(n);
System.out.println(Thread.currentThread().getName()+"结束");
线程的互斥
- 由于基本类型难于附加更多机制,因此Java将资源
限定为引用型对象,并为每一对象自动配备一把锁。 - 锁初始时,是处于打开状态。
- synchronized标记的原子代码段在访问资源前,会自动检测资源对象持有的锁是否处于打开状态。如果是,则占用并同时将锁置为锁闭状态。并在该代码段执行完牛后,将锁的状态值设为打开状态。如果自动检测到资源对象持有的锁处于锁闭状态,则持有该代码段的线程因等待资源占用而进入阻塞
synchronized标记的两种方法
- 插入代码块
synchronized(竞争临界资源)原子操作
- 作为函数的声明
public synchronized void f()...
等价于
public void f()synchronized (this)...
实例
共享打字机
public class Work1
public static void main(String[] args)
String flag = "flag";
String[] work1 = "1","3","5","7","9";
String[] work2 = "2","4","6","8","10";
String[] work3 = "3","6","9","12";
Work_1 w1 = new Work_1(flag,"甲",work1);
Work_1 w2 = new Work_1(flag,"乙",work2);
Work_1 w3 = new Work_1(flag,"丙",work3);
w1.start();
w2.start();
w3.start();
class Work_1 extends Thread
private String flag;
private String name;
private String[] content;
public Work_1(String f,String n,String[] c)
flag = f;
name = n;
content = c;
public void run()
synchronized (flag)
System.out.print(name+":");
for(String x:content) System.out.print(" "+x);
System.out.println();
多窗口售票
import java.util.Arrays;
public class Work3
public static void main(String[] args)
int[] data = new int[100];
for(int i = 0;i<100;i++)
data[i] = i;
Pos pos = new Pos(data.length);
Buy w1 = new Buy(pos,data,"一号");
Buy w2 = new Buy(pos,data,"二号");
Buy w3 = new Buy(pos,data,"三号");
Buy w4 = new Buy(pos,data,"四号");
w1.start();
w2.start();
w3.start();
w4.start();
class Buy extends Thread
private int data[];
private int over[];
private String name;
private Pos pos;
public Buy(Pos p,int[] d,String n)
pos = p;
data = d;
name = n;
over = new int[data.length];
public void run()
while (true)
try
sleep(10);
catch (InterruptedException e)
e.printStackTrace();
synchronized (pos)
int x = pos.getPos();
if(x==-1) return;
int tic = data[x];
System.out.println(name+"窗口售出"+tic+"号票");
class Pos
private int max,pos;
public Pos(int m)
max = m;
pos=0;
public int getPos()
if (pos==max) return -1;
int x = pos; pos++; return x;
线程的同步
对于线程的同步思想,可以用一个例子来理解
一群人去登山,大家分头走,走到集合点的时候就先等待着,等到所有人都到达了集合点后,再进行下一步的行动
这里体现了同步的策略:互斥+通信
互斥,就是线程之间有着临界资源,这个资源的状态决定线程是否能执行
通信,就是对临界资源的wait(),notify(),notifyAll()的调用,决定线程走到这里是阻塞还是放行
再看这几个函数
- wait()函数,让该线程阻塞住,一般是来等待所有线程的同步
- notify(),notifyAll(),唤醒线程,若有多个线程,则使用notifyAll去唤醒所有线程
- join(),在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。这个函数可以用于main方法中,
线程.join()
后,main线程会阻塞,当所有线程结束,main线程会被唤醒
实例1
有三个数组如下
1,3,5,7,9
2,4,6,8,0
a,b,c,d,e
要求通过三个线程,分别按顺序输出内容,如下所示
12a 24b 36c 。。。。
这就要求了,三个线程在运行的时候,输出完第一个元素,要先等着,等到所有线程都输出完了第一个元素,再放行去输出第二个元素
可以这样去实现
思想是利用一个count,每次输出加一,通过计算count%3来判断是否输完一轮
public class Work1
static int count = 1;
public static void main(String[] args)
String[] a = "1","3","5","7","9";
String[] b = "2","4","6","8","0";
String[] c = "a","b","c","d","e";
Source out = new Source();
OutPut out1 = new OutPut(out,a);
OutPut out2 = new OutPut(out,b);
OutPut out3 = new OutPut(out,c);
out1.start();
out2.start();
out3.start();
try
out1.join();
out2.join();
out3.join();
catch (InterruptedException e)
e.printStackTrace();
System.out.println("结束");
class Source
public void outStr(String data)
System.out.print(data);
if (Work1.count % 3 == 0)
Work1.count++;
notifyAll();
else
try
Work1.count++;
wait();
catch (InterruptedException e)
e.printStackTrace();
class OutPut extends Thread
private Source sou;
private String[] data;
private final int turn = 5;
public OutPut(Source s,String[] a)
sou = s;
data = a;
public void run()
for(int i = 0;i<turn;i++)
synchronized(sou)
sou.outStr(data[i]);
也可以这样实现他
以上是关于[Java多线程]线程创建的三种方式,线程的互斥,线程的同步的主要内容,如果未能解决你的问题,请参考以下文章
[Java多线程]线程创建的三种方式,线程的互斥,线程的同步