目录
一、多线程的创建
方式一:
(Thread.currentThread().getName() :返回当前线程的名字)
/**
1、创建一个继承于Thread的子类
2、重写Thread类的run()--- 将此线程执行的操作写在该方法中
3、创建Thread类的子类对象
4、通过此对象调用start()
*/
public class ThreadTest {
public static void main(String[] args) {
//3、创建Thread类的子类的对象
MyTread myThread = new MyTread();
//4、通过此对象调用start() 作用:启动当前线程;调用当前线程的run()
//不可以让已经start()过的再次start()--要重新创建对象调用start()方法
myThread.start();
//main()线程中执行
// for (int i=0;i<=100;i++){
// if (i%2==0){
// //Thread.currentThread().getName() :返回当前线程的名字
// System.out.println(Thread.currentThread().getName() + ": yeah");
// }
// }
}
}
// 1、创建一个继承于Thread的子类
class MyTread extends Thread{
//2、重写Thread类的run()
@Override
public void run() {
//打印100以内的偶数
for (int i=0;i<=100;i++){
if (i%2==0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
方式二:
/*
方式二:实现Runnable接口
1) 定义子类,实现Runnable接口。
2) 子类中重写Runnable接口中的run方法。
3) 通过Thread类含参构造器创建线程对象。
4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
*/
public class ThreadTest2 {
public static void main(String[] args) {
//3) 通过Thread类含参构造器创建线程对象
MThread mThread1 = new MThread();
//4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中
Thread t = new Thread(mThread1); //此处创建Thread的对象,调用Thread线程的有参构造器,将mThread1赋给构造器中的target,然后调用target的run()方法
//5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法
t.start();
//此时实现类mThread1共享,只需要重新将子类对象作为实际参数传递给Thread类的构造器中
Thread t1 = new Thread(mThread1);
t1.start();
}
}
//1) 定义子类,实现Runnable接口
class MThread implements Runnable{
//2) 子类中重写Runnable接口中的run方法
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
}
}
方式三:实现Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//创建线程方式三:实现Callable接口
public class CallableTest {
public static void main(String[] args) {
//3、创建Callable接口实现类的对象
newThread newThread = new newThread();
//4、借助FutureTask类,创建FutureTask类的对象,并将实现类的对象传入FutureTask的构造器中
FutureTask futureTask = new FutureTask(newThread);
//5、将FutureTask类的对象传入Thread构造器中,创建Thread类的对象, 并启动线程
Thread thread = new Thread(futureTask);
thread.start();
//6、调用FutureTask类的get()方法--获取call()方法的返回结果
try {
Object sum = futureTask.get();
System.out.println("the total is : " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//1、实现Callable类
class newThread implements Callable{
//2、重写call()方法 将需要执行的操作声明在call()方法中
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i%2==0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
方式四:使用线程池创建多线程 (...)
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
//1 提供指定线程数得线程池
ExecutorService service = Executors.newFixedThreadPool(5);
//2 执行执行线程操作 需要提供实现Runnable接口或Callable接口实现类得对象
service.execute(new myPool1()); //适用于runnable接口
service.execute(new myPool2());
//service.submit(Callable callable); 适用于Callable接口
//3 关闭线程池
service.shutdown();
}
}
class myPool1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 40; i++) {
if (i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
二、小练习
创建两个分线程,分别打印100以内的偶数和奇数
public class ThreadTest {
public static void main(String[] args) {
//创建创建Thread类的子类的对象
MyTread myThread = new MyTread();
MyThread1 myThread1 = new MyThread1();
//通过此对象调用start() 作用:启动当前线程;调用当前线程的run()
//不可以让已经start()过的再次start()--要重新创建对象调用start()方法
myThread.start();
myThread1.start();
}
}
/*
方式一:继承于Thread类的子类
1、创建一个继承于Thread的子类
2、重写Thread类的run() --将此线程执行的操作写在该方法中
3、创建Thread类的子类的对象
4、通过此对象调用start()
*/
class MyTread extends Thread{
@Override
public void run() {
for (int i=0;i<=100;i++){
if (i%2==0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for (int i=0;i<=100;i++){
if (i%2==1){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
/*
创建Thread类的匿名子类的方式
new className(){
@Override
public void run() {
//重写的run()方法
}
}.start();
*/
new MyTread(){
@Override
public void run() {
for (int i=0;i<=100;i++){
if (i%2==0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}.start();
三、Thread常用方法
/**
* 1、setName() 设置当前线程名称
* 2、getName() 获取当前线程名称
* 3、currentThread() 静态方法 返回执行当前代码的线程
* 4、yield() 释放当前cpu的执行权
* 5、join() 在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到线程b执行完毕,才会结束线程a的阻塞状态,开始执行线程a
* 6、sleep(time) 让指定线程睡眠,指定线程此时属于阻塞状态
* 7、isAlive() 判断当前线程是否存活 返回true or false
*/
Thread1 thread1 = new Thread1();
//设置thread1的线程名
thread1.setName("线程一");
thread1.start();
for (int i = 0; i < 50; i++) {
//当main线程中的i==25时,main()进入阻塞状态,开始执行thread1线程
if (i == 25){
try {
//在main线程中调用thread1线程的join()方法
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
四、线程的优先级
/**
* 线程的优先级
* 1、优先级别
* MAX_PRIORITY:10
* MIN _PRIORITY:1
* NORM_PRIORITY:5 默认优先级
* 2、获取和设置优先级
* setPriority()
* getPriority()
*/
//获取和设置优先级
System.out.println(thread1.getPriority()); //5
thread1.setPriority(Thread.MAX_PRIORITY);
五、同步机制
1、通过同步机制来解决线程安全问题
(1)同步代码块
/**
* 同步机制:
* 方式一:同步代码块
* synchronized (对象){
* // 需要被同步的代码;
* }
* (1)操作共享数据的代码,即为需要被同步的代码
* (2)共享数据:多个线程共同操作的变量(如ticket)
* (3)同步监视器(锁),任何一个类的对象都可以(要求:多个线程必须公用同一把锁)
*/
//同步代码块解决runnable线程安全问题
public class SoldTicketTest1 {
public static void main(String[] args) {
//只创建了一个SoldTicket1对象,类中属性共享
SoldTicket1 soldTicket1 = new SoldTicket1();
Thread thread1 = new Thread(soldTicket1);
Thread thread2 = new Thread(soldTicket1);
Thread thread3 = new Thread(soldTicket1);
thread1.setName("window 1");
thread2.setName("window 2");
thread3.setName("window 3");
thread1.start();
thread2.start();
thread3.start();
}
}
class SoldTicket1 implements Runnable {
private int ticket = 100;
//公用同一把锁
// Object obj = new Object();
@Override
public void run() {
while (true) {
//同步代码块:obj是锁
// synchronized(obj) {
synchronized (this){ //this:唯一的SoldTicket1的对象即soldTicket1
//操作共享变量(ticket)的代码块
if (ticket > 0) {
//增大线程不安全的概率
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
ticket--;
} else
break;
}
}
}
}
//同步代码块解决继承中的线程安全问题
public class SoldTicketTest2 {
public static void main(String[] args) {
//声明了三个对象
SoldTicket2 s1 = new SoldTicket2();
SoldTicket2 s2 = new SoldTicket2();
SoldTicket2 s3 = new SoldTicket2();
//修改线程名称
s1.setName("window 1 ");
s2.setName("window 2 ");
s3.setName("window 3 ");
//启动线程
s1.start();
s2.start();
s3.start();
}
}
class SoldTicket2 extends Thread{
//设置static共享
private static int ticket = 100;
//公用同一把锁(继承中必须设置为static才能共享)
private static Object obj = new Object();
@Override
public void run() {
while (true) {
//同步代码块:obj是锁
synchronized(obj) {
//synchronized (SoldTicket2.class){ //SoldTicket2.class:当前类,只会加载一次,可行
//synchronized(this) { 在使用继承的方式创建线程:不能直接使用this:代表s1 s2 s3 不是同一把锁
//操作共享变量(ticket)的代码块
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
ticket--;
} else
break;
}
}
}
}
(2)、同步方法
//使用synchronized方法解决runnable线程安全问题
public class SoldTicketTest3 {
public static void main(String[] args) {
SoldTicket3 soldTicket = new SoldTicket3();
Thread thread1 = new Thread(soldTicket);
Thread thread2 = new Thread(soldTicket);
Thread thread3 = new Thread(soldTicket);
thread1.setName("window 1");
thread2.setName("window 2");
thread3.setName("window 3");
thread1.start();
thread2.start();
thread3.start();
}
}
class SoldTicket3 implements Runnable{ //此时锁是this
private int ticket = 100;
@Override
public void run() {
while (true){
//调用类中的synchronized方法
show();
}
}
//将操作共享数据的代码封装在一个synchronized方法中
private synchronized void show(){
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
ticket--;
}
}
}
//使用synchronized方法解决继承中的线程安全问题
public class SoldTicketTest4 {
public static void main(String[] args) {
//声明了三个对象
SoldTicket4 s1 = new SoldTicket4();
SoldTicket4 s2 = new SoldTicket4();
SoldTicket4 s3 = new SoldTicket4();
//修改线程名称
s1.setName("window 1 ");
s2.setName("window 2 ");
s3.setName("window 3 ");
//启动线程
s1.start();
s2.start();
s3.start();
}
}
class SoldTicket4 extends Thread{
//设置static共享
private static int ticket = 100;
//公用同一把锁(继承中必须设置为static才能共享)
private static Object obj = new Object();
@Override
public void run() {
while (true) {
show();
}
}
//将synchronized方法声明为static 才是同一把锁(SoldTicket4.class)
private static synchronized void show(){
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " sold_ticket: " + ticket);
ticket--;
}
}
}
2、Lock
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用Lock解决Runnable中线程安全问题
* class A{
* private final ReentrantLock lock = new ReenTrantLock();
* public void m(){
* lock.lock();
* try{
* //保证线程安全的代码; }
* finally{
* lock.unlock();
* } } }
*/
public class LockTest {
public static void main(String[] args) {
SoldTicket5 soldTicket5 = new SoldTicket5();
Thread t1 = new Thread(soldTicket5);
Thread t2 = new Thread(soldTicket5);
Thread t3 = new Thread(soldTicket5);
t1.setName("window 1");
t2.setName("window 2");
t3.setName("window 3");
t1.start();
t2.start();
t3.start();
}
}
class SoldTicket5 implements Runnable {
private int ticket = 100;
//通过显式定义同步锁对象来实现同步,同步锁使用Lock对象充当
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
//显示加锁
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": " + ticket);
ticket--;
}
} finally {
//解锁
lock.unlock();
}
}
}
}
六、进程通信
/**
* 线程通信:
*
* 线程通信方法:(1、以下三个方法必须使用在同步代码块或同步方法中 2、三个方法的调用者必须是同步代码块或同步方法中的同步监视器)
* wait(): A线程执行此方法,进入阻塞状态,释放同步监视器,则B线程可以拿到此监视器
* notify(): B线程执行此方法,就会唤醒一个被wait()的线程,如果有多个被wait()线程,则唤醒优先级较高的那一个线程
* notifyAll(): 执行此方法,就会唤醒所有被wait()的线程
*/
//使用两个线程交替打印 1-100
public class ThreadCommunication {
public static void main(String[] args) {
Communication c = new Communication();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.setName("Thread 1");
t2.setName("Thread 2");
t1.start();
t2.start();
}
}
//实现Runnable
class Communication implements Runnable{
private int number = 1;
// Object obj = new Object();
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public void run() {
while (true){
//实现类 采用synchronized方法,锁可以直接用this(指Communication的对象)
synchronized (this) {
//调用notify()的线程释放阻塞进程 比如线程1进来--打印--线程1阻塞--线程2进来--释放线程1--打印--线程2阻塞--线程1进来--释放线程2--打印...
notify(); //其实是this.notify();
//obj.notify();
//延迟
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (number <= 100){
System.out.println(Thread.currentThread().getName() + ": " + number);
number++;
}else{
break;
}
//调用wait()的线程进入阻塞状态
try {
wait(); //其实是this.wait();
// obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}