Java多线程
创建线程有四种方法,让我们来一一见识一下吧!
创建多线程方法1
1.自己写一个类继承Thread类
2…重写父类的run()方法
3.创建自己写的类的对象
4.利用对象名.start()方法来创建线程
class MyFrame extends Thread{ //1.自己写一个类继承Thread类
public void run(){ //2.重写父类的run()方法
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(i);
}
}
}
}
public class Test5 {
public static void main(String[] args) {
MyFrame s=new MyFrame(); //主线程
s.start(); //另一个线程
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(i+"****************"); //输出结果会乱序!
}
}
}
}
Thread类的方法
/*
* Thread类的方法
* 1.strat()方法:启动当前线程,调用Thread类重写的run()方法
* 2.run()方法:将创建的线程要执行的操作声明在此方法中
* 3.currentThread():静态代码,返回执行当前代码的线程
* 4.getName():返回当前线程的名字
* 5.setName():设置当前线程的名字
* 6.yield(): 释放当前cpu的执行权(但是有可能又被当前线程占用,只是说其他线程机会要大一些,但不绝对!)
* 7.join(): 在线程A中调用线程B的join()方法,则线程A进入阻塞状态,当线程B执行完以后再执行A!
* 8.stop(): 已过时,当执行此方法,强制结束当前线程(一般不建议使用!)
* 9.sleep(long milltime): 让当线程休息,单位为毫秒!
* 10.isAlive(): 判断线程是否还存活!
*
* 线程的优先级:
* MAX_PRIORITY: 10
* MIN_PRIORITY: 1
* NORM_PRIORITY: 5(一般默认为5)
* getPriority():获得线程的优先级!
* setPriority():设置线程的优先级!
*/
class MyFrame1 extends Thread{
public void run(){
for(int i=0;i<100;i++){
if(i%2 == 0){
try{sleep(10000);
} //因为sleep原函数会抛异常,所以用try catch语句
catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class Test7 {
public static void main(String[] args) {
MyFrame s=new MyFrame(); //主线程
s.setName("线程一"); //修改线程名
s.start(); //另一个线程 只能调用一次!
s.currentThread().setName("主线程"); //修改主线程名
try{s.join();}
catch (Exception e){
e.printStackTrace(); //和sleep()的用法一样!
}
for(int i=0;i<100;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+":"+i+"****************"); //输出结果会乱序!
}
}
System.out.println(s.isAlive());
}
}
创建线程的第二种方法
/*
* 创建线程的第二种方法!:实现Runnable接口
* 1.创建一个实现了Runnable接口的类
* 2.类去实现Runnable接口中的run()方法
* 3.创建实现类的对象
* 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
* 5.通过Thread类的对象调用start()方法
*/
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i%2 == 0){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
public class Test8 {
public static void main(String[] args) {
MyRunnable s = new MyRunnable();
Thread th1 = new Thread(s);
th1.setName("线程一");
th1.start();
}
}
创建线程的第二种方法的实例
//实现三个窗口卖票
class MyRunnable implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
if(ticket > 0){
System.out.println(Thread.currentThread().getName()+"卖票 票号:"+ticket);
ticket--;
}
else{
break;
}
}
}
}
public class Test8 {
public static void main(String[] args) {
MyRunnable s = new MyRunnable();
Thread th1 = new Thread(s);
Thread th2 = new Thread(s);
Thread th3 = new Thread(s);
th1.setName("窗口一");
th2.setName("窗口二");
th3.setName("窗口三");
th1.start();
th2.start();
th3.start();
}
}
上面的输出结果你会发现是乱序的,原因就是发生了线程的安全问题!
线程的安全问题
/*
* 1.问题:上个例子会出现错票和重票的问题! -->出现了线程的安全问题
* 2.问题出现的原因:当某个线程操作的过程中,尚未操作完成,其他的线程也进入来操作!
* 3.如何解决:当某一个线程操作的过程中,我们给它加一把锁,当这个线程操作完成过后,其他线程才能进入操作!
* 注:即使当前线程被阻塞,其他的线程也不能够进入!
* 4.在Java中,利用同步机制来解决这个问题!
* 方法一:同步代码块
* synchronizedh(同步监视器){
* //需要被同步的代码(即对共享资源的操作)
* }
* 注:1.操作共享数据的代码,即需要被同步的代码。
* 2.共享数据,多个线程共同操作的变量。比如:ticket
* 3.同步监视器,俗称锁,任何一个类的对象都可以充当锁。
* 4. 要求:多个线程必须共用同一把锁!
*/
class MyRunnable1 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket > 0) {
try{
Thread.sleep(1000); //静态方法
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class Test9 {
public static void main(String[] args) {
MyRunnable1 s = new MyRunnable1();
Thread th1 = new Thread(s);
Thread th2 = new Thread(s);
Thread th3 = new Thread(s);
th1.setName("窗口一");
th2.setName("窗口二");
th3.setName("窗口三");
th1.start();
th2.start();
th3.start();
}
}
使用第一种方法的实例
class MyFrame2 extends Thread{
private static int ticket = 100;
private static Object obj = new Object(); //设置为静态对象
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket > 0) {
try{
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "卖票 票号:" + ticket);
ticket--;
} else {
break;
}
}
}
}
}
public class Test10 {
public static void main(String[] args) {
MyFrame2 x1 = new MyFrame2();
MyFrame2 x2 = new MyFrame2();
MyFrame2 x3 = new MyFrame2();
x1.setName("窗口1");
x2.setName("窗口2");
x3.setName("窗口3");
x2.start();
x1.start();
x3.start();
}
}
同步方法
1.用接口实现
class MyRunnable3 implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true) {
show();
}
}
public synchronized void show(){ //同步方法
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
ticket--;
}
}
}
public class Test11 {
public static void main(String[] args) {
MyRunnable1 s = new MyRunnable1();
Thread th1 = new Thread(s);
Thread th2 = new Thread(s);
Thread th3 = new Thread(s);
th1.setName("窗口一");
th2.setName("窗口二");
th3.setName("窗口三");
th1.start();
th2.start();
th3.start();
}
}
2.用继承实现
class MyFrame4 extends Thread{
private static int ticket = 100;
private static Object obj = new Object();
@Override
public void run() {
while (true) {
show();
}
}
public static synchronized void show(){ //监视器为 MyFrame4.class
if (ticket > 0) {
try{
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
ticket--;
}
}
}
public class Test12 {
public static void main(String[] args) {
MyFrame4 x1 = new MyFrame4();
MyFrame4 x2 = new MyFrame4();
MyFrame4 x3 = new MyFrame4();
x1.setName("窗口1");
x2.setName("窗口2");
x3.setName("窗口3");
x2.start();
x1.start();
x3.start();
}
}
线程的死锁
/*
* 线程的死锁的问题
* 1.死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,
* 都在等待对方放弃自己需要的同步资源,就形成了线程死锁!
*
* 2.说明:
* 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于堵塞状态,无法继续
*
* 举一个例子:人吃饭要两双筷子,现在桌子上有两双筷子,有两个人,让他们去抢,结果肯定有三种情况,一人一支筷子
* 就相当于死锁,都在等对方放弃自己的资源!
*/
public class Test13 {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer();
StringBuffer s2 = new StringBuffer();
new Thread(){
@Override
public void run() {
synchronized (s1){
s1.append("1");
s2.append("a");
try {
sleep(100); //增加死锁的概率
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2){
s1.append("2");
s2.append("b");
System.out.println(s1);
System.out.println(s2);
}
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2){
s1.append("3");
s2.append("c");
try {
Thread.sleep(100); //增加死锁的概率
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1){
s1.append("4");
s2.append("d");
System.out.println(s1);
System.out.println(s2);
}
}
}
}).start();
}
}
线程安全问题解决方案三:Lock锁
import java.util.concurrent.locks.ReentrantLock;
/*
* 解决线程安全问题的方式三:Lock锁
*
*/
class MyRunnable5 implements Runnable{
private int ticket = 100;
private ReentrantLock lock1= new ReentrantLock(); //1.定义一个ReentrantLock类的对象!
@Override
public void run() {
while (true) {
lock1.lock(); //2.使用lock()方法锁住
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖票 票号:" + ticket);
ticket--;
lock1.unlock(); //3.使用unlock()方法解锁
}
}
}
}
public class Test14 {
public static void main(String[] args) {
MyRunnable1 s = new MyRunnable1();
Thread th1 = new Thread(s);
Thread th2 = new Thread(s);
Thread th3 = new Thread(s);
th1.setName("窗口一");
th2.setName("窗口二");
th3.setName("窗口三");
th1.start();
th2.start();
th3.start();
}
}
线程通信
-
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
-
notify():一旦执行此方法,就会唤醒被wait()的一个线程,如果有多个线程被wait(),就会唤醒优先级高的线程
-
notifyAll():一旦被执行,就会唤醒所以被wait的线程
-
说明:
-
1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中
-
2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器
-
否则会出现异常
-
3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中的
/* 1.线程通信
* wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
* notify():一旦执行此方法,就会唤醒被wait()的一个线程,如果有多个线程被wait(),就会唤醒优先级高的线程
* notifyAll():一旦被执行,就会唤醒所以被wait的线程
*
* 说明:
* 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中
* 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器
* 否则会出现异常
* 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中的
*/
class MyThread6 implements Runnable{
int number = 0;
@Override
public void run() {
while(true){
synchronized (this) {
notify();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(number <= 100){
System.out.println(Thread.currentThread().getName()+": "+number);
number++;
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Test16 {
public static void main(String[] args) {
MyThread6 s = new MyThread6();
Thread th1 = new Thread(s);
Thread th2 = new Thread(s);
th1.setName("线程一");
th2.setName("线程二");
th1.start();
th2.start();
}
}
线程通信的一个例题
现有店员 顾客 生产者,当生产者生产到20,店员就会告诉他停一下再生产,当店里没有东西时,店员就会告诉顾客让他等一下再购买!
class Clerk{
int produceNumber = 0;
public synchronized void Reduce() {
if (produceNumber > 0) {
produceNumber--;
System.out.println(Thread.currentThread().getName() + "开始消费,产品还剩" + produceNumber);
notify();
}
if(produceNumber == 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void Add(){
if (produceNumber < 20){
produceNumber++;
System.out.println(Thread.currentThread().getName()+"开始生产,产品有"+produceNumber);
notify();
}
if(produceNumber == 20){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Customer extends Thread{
private Clerk cle;
public Customer(Clerk cle){
this.cle=cle;
}
@Override
public void run() {
while (true) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
cle.Reduce();
}
}
}
class Producer extends Thread{
private Clerk cle;
public Producer(Clerk cle){
this.cle=cle;
}
@Override
public void run() {
while (true) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
cle.Add();
}
}
}
public class Test17{
public static void main(String[] args) {
Clerk cle = new Clerk();
Customer cus = new Customer(cle);
Producer pro = new Producer(cle);
cus.setName("顾客");
pro.setName("生产者");
cus.start();
pro.start();
}
}
创建线程方法三
/* 创建线程的方法三:
* 1.创建一个类实现Callable接口
* 2.创建一个实现了Callable接口的类的对象
* 3.将该对象作为参数传递到FutureTask类的构造器,并构造对象!
* 4.将FutureTask类的对象作为参数传递到Thread类的构造器!
* 5.调用Thread类对象.start()方法
* 6.如果需要实现了Callable接口类call方法的返回值,则调用FutureTask类的对象.get()
*
*/
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class NumThread implements Callable{
@Override
public Object call() throws Exception {
int sum = 0;
for (int i = 0; i <100 ; i++) {
if (i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class Test18 {
public static void main(String[] args) {
NumThread numThread = new NumThread();
FutureTask futureTask = new FutureTask(numThread);
new Thread(futureTask).start();
try {
Object sun = futureTask.get();
System.out.println("总和为:"+sun);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
创建线程方法四
/* 利用线程池来创建线程
*
*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class NumberThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i%2==0){
System.out.println(i);
}
}
}
}
public class Test19 {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10); //设置线程池的大小
service.execute(new NumberThread()); //运行run方法
service.shutdown(); //关闭线程池
}
}
如果本篇文章对您有些帮助的话,点个赞,激励一下博主!嘻嘻!