这两篇文章写得真的好:
文章目录
两种实现方式:
- 继承
Thread
类 - 实现
Runnable
接口
继承Thread
类
构造Thread 实例- public Thread() - public Thread(String threadName) 创建名为 ThreadName 的线程对象 |
public class Test extends Thread
{
private int count=10;
public void run(){
while(true){
System.out.printlnl(count + "");
if(--count==0){
return;
}
}
}
public static void main(String[] args){
new Test().start();
}
}
- 实现线程的代码写在
run
方法中 - 调用
start
方法执行线程(调用run()
方法) - 主方法调用
start
方法前,Thread
对象仅是一个实例,并不是线程
实现Runnable
接口
实现Runnable 接口语法:public class Thread Extends Object implements Runnable 构造方法: public Thread(Runnable target) public Thread(Runnable target, String name) 于是实现了将 Runable 实例与Thread 实例相关联 |
使用Runnable
接口启动新线程的步骤如下:
- 建立
Runnable
对象 - 使用参数为
Runnable
对象的构造方法创建Thread
实例 - 调用
start
方法启动线程
Thread t = new Thread(new Runnable(){
public void run(){
while(..){
...
}
}
t.start();
线程的生命周期
状态 | 说明 |
---|---|
出生 | start() 调用之前都处于出生状态 |
就绪 | 调用start() 后,就绪 |
运行 | 线程得到系统资源后,运行 |
等待 | 调用wait() ,等待。调用notify() 唤醒 |
休眠 | 调用sleep() 后,休眠 |
阻塞 | 运行时发出输入 、输出 请求,阻塞 |
死亡 | run() 执行完毕后,死亡 |
- 使线程进入就绪状态
-
sleep()
-
wait()
- 等待输入、输出完成
- 使线程由就绪到运行
-
notify()
-
notifyAll()
唤醒所有等待状态线程 -
interrupt()
- 休眠时间结束
- 输入、输出结束
线程的加入 join()
- 某线程使用
join()
方法加入另一线程时,另一线程会等待该线程执行完毕再执行。
Thread threadA = new Thread(new Runnable(){
int count=0;
public void run(){
while(true){
...
threadB.join();
}
}
}
线程让步
Thread.yield()
方法。暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
线程的优先级 setPriority()
- 新线程继承父类优先级
- 优先级
1-10
常数 | 优先级 |
---|---|
Thread.MAX_PRIORITY | 10 |
Thread.MIN_PRIORITY | 1 |
Thread.NORM_PRIORITY | 5 |
Thread thread_a = new Thread();
setPriority("thread_a", 5, thread_a);
thread_a.setPriority(5);
thread_a.setName(name); //设置线程名字
线程同步
- 线程同步机制——解决资源访问冲突
线程同步机制
同步块 synchronized
- 把共享资源放在同步块(临界区)
synchronized(Object){
}
同步方法 synchronized
- 必须将每个能访问共享资源的方法修饰为
synchronized
synchronized void func(){
}
public synchronized void doit(){
if(num>0){
try{
Thread.sleep(10);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("tickets" + --num);
}
}
public void run(){
while(true){
doit();
}
}
synchronized 具体应用
- 实例方法
- 静态方法
- 同步代码块
1. 作用于实例方法
public class Test implements Runnable{
//共享资源/临界资源
static int i=0;
// synchronized 修饰实例方法
public synchronized void increase(){
i++;
}
@Override
public void run() {
for(int j=0;j<1000;j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Test instance=new Test();
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
输出:
>>> 2000
- 如果实例不同,那就是不同的实例方法,谁也锁不着谁了。
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(new Test());
Thread t2=new Thread(new Test());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
2. 作用于静态方法
public class Test implements Runnable{
static int i=0;
// 作用于静态方法,锁是当前class对象
public static synchronized void increase(){
i++;
}
// 非静态,访问时锁不一样(实例对象不一样) 不会 发生互斥
public synchronized void increase4Obj(){
i++;
}
@Override
public void run() {
for(int j=0;j<1000000;j++){
increase();
}
}
public static void main(String[] args) throws InterruptedException {
//new新实例
Thread t1=new Thread(new Test());
//new另一个实例
Thread t2=new Thread(new Test());
//启动线程
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);
}
}
- 作用于静态方法,就不用但是实例对象不一样的问题了。
3. 同步代码块
public class Test implements Runnable{
static Test instance=new Test();
static int i=0;
@Override
public void run() {
//...do something...
//锁对象为instance
synchronized(instance){
for(int j=0;j<1000000;j++){
i++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(instance);
Thread t2=new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(i);
}
}
- 实例对象锁【同上】
public static void run(){
synchronized(this){
for(...){
...
}
}
}
- class对象锁
public static void run(){
synchronized(Test.class){
for(...){
...
}
}
}
import static java.lang.System.out;
import java.util.*;
import Tools.Tools;
// 同步代码块
public class TrySome implements Runnable{
// 用于 run() for循环中累加
static int value = 0;
// 计算 list 中数值求和
static int sum=0;
// 记录 list 中最大、最小值
static double max=0, min=Double.POSITIVE_INFINITY;
// 创建一 int ArrayList
static List<Integer> list = new ArrayList<>();
// 这是自己编写的一个简单工具类
static Tools tool = new Tools();
private String name="None";
private String say="None";
// 构造方法
public TrySome(String name, String words)
{
this.name = name;
this.say = words;
}
public TrySome(){}
// run() 方法
public void run()
{
out.println("I am " + name + ". I say: " + say);
synchronized(TrySome.class){
for(int i=0;i<2e5;i++)
{
value++;
}
mk_list();
Iterator<Integer> itr = list.iterator();
while(itr.hasNext())
{
int data = itr.next();
sum += data;
if(data>max)
{
max = data;
}
if(data<min)
{
min = data;
}
}
}
}
public static void mk_list()
{
for(int i=0;i<40;i++)
{
list.add(tool.randint(20, 200));
}
}
public static void main(String[] args) throws Exception
{
Thread t1 = new Thread(new TrySome("Fry", "Hello future!"));
Thread t2 = new Thread(new TrySome("Bender", "Bite my shiny metal ass!"));
t1.start();t2.start();t2.join();
out.println(value);
// ==========================================
out.println("average: "+ (sum/80) + " max:" + max + " min: " + min);
}
}
import static java.lang.System.out;
import java.util.*;
import Tools.Tools;
public class FurtherM implements Runnable{
List<Double> list = new ArrayList<>();
static double sum=0;
static List<Double> summ = new ArrayList<>();
static Tools t = new Tools();
String name;
public FurtherM(List<Double> lst, String name)
{
list = lst;
this.name = name;
}
public void run()
{
Iterator<Double> itr = list.iterator();
synchronized(FurtherM.class)
{
while(itr.hasNext())
{
sum += itr.next();
}
}
out.println(name + " is over!");
}
public static List<Double> mk_list()
{
List<Double> lst = new ArrayList<>();
double sumall=0;
for(int i=0;i<40;i++)
{
double data = t.randf_format(1, 1, 40);
sumall += data;
lst.add(data);
}
summ.add(sumall);
out.println(sumall);
return lst;
}
public static void main(String[] args) throws InterruptedException
{
Thread t1 = new Thread(new FurtherM(mk_list(), "One"));
Thread t2 = new Thread(new FurtherM(mk_list(), "Two"));
t1.start();t2.start();
t1.join();t2.join();
out.println("sum: " + sum);
out.println("allsum: " + (summ.get(0) + summ.get(1)));
}
}
Tools
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Random;
/*****************************************************************
* ****** 属性 *******
* - d : Date()
* - r : Random()
* - myFormat : DecimalFormat()
*
* --------方法-------------
* print(Number...) | print(String)
* format_(pattern, data)
* randint(from, to) | randf(from, to)
* randf_format(n, from, to) -- 小数位数 n 位
*
*
******************************************************************/
public class Tools {
Date d = new Date();
int seed = Integer.parseInt(String.format("%ts", d));
Random r = new Random(seed);
DecimalFormat myFormat = new DecimalFormat();
public void print(String s) {
System.out.println(s);
}
public void print(Number... a) {
StringBuilder s = new StringBuilder();
for (Number j : a) {
s.append(j).append("\t");
}
System.out.println(s);
}
public String format_(String pattern, double data) {
myFormat.applyPattern(pattern);
return myFormat.format(data);
}
public int randint(int from, int to) {
return from + (int) (r.nextInt(to - from));
}
public double randf(double from, double to) {
return from + (to - from) * r.nextDouble();
}
/***********************************************
// return double
// n:小数位数 from ~ to
************************************************/
public double randf_format(int n, double from, double to) {
StringBuilder pattern = new StringBuilder("0.");
pattern.append("0".repeat(n));
String s = this.format_(pattern.toString(), randf(from, to));
return Double.parseDouble(s);
}
}