进程!
package Thread;
/*
*多线程的创建:方式一
- 1.创建一个继承与thread类的子类
- 2.重写thread 的run方法—》将线程要做的方法写在run方法中
- 3.创建继承thread的类的对象
- 4.通过子类对象调用start()方法
*例子:遍历100以内的所有偶数。
*问题一:我们不能通过通过对象.run()启动线程,启动线程必须是start()
*问题二:在启动一个线程,遍历100以内的偶数
*不可以,会报异常,一个对象的线程只能调用一次 - */
public class day01 extends Thread{
public static void main(String[] args) {
//创建子类的实例化对象
day01 test = new day01();
day01 test1 = new day01();
//4.调用start()方法。
//启动当前线程②:调用当前线程的run方法
test.start();
// 问题二:在启动一个线程,遍历100以内的偶数
test1.start();
//test.run();没有启动线程,只是调用了run方法。
//如下的方法操作仍然在main县城中执行
for (int i = 0;i<=100;i++){
if (i %2 ==0){
System.out.println(
Thread.currentThread().getName()+i + “**main”);
}
}
}
//重写run方法
@Override
public void run() {
for (int i = 0;i<=100;i++){
if (i %2 ==0){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
}
练习
package test;
/*
-
练习:创建两个线程,
-
其中一个遍历一个100以内的偶数,
-
另一个遍历100以内的奇数
-
*/
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
MyThread1 myThread1 = new MyThread1();
myThread.start();
myThread1.start();//创建匿名子类 /* new Thread() { @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } }.start(); new Thread() { @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 != 0) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } }.start();*/
}
class MyThread 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 != 0) {
System.out.println(Thread.currentThread().getName() + “:” + i);
}
}
}
}
thread的常用method
package test;
/*
-
测试Thread中常用的方法:
-
1.start():启动当前线程,调用run方法
-
2.run():通常需要重写thread类的此方法,将创建的线程要执行的操作声明在run()方法中
-
currentThread():静态方法,返回执行当前代码的线程
-
getName():获取当前线程的名字
-
setName():设置当前线程的名字:也可以通过构造器进行setname
*yield():释放当前cpu的执行权, -
join():在线程a中调用线程b的join()方法,线程a就进入了阻塞状态,直到线程b执行完毕,线程a才结束阻塞状态
-
stop():强制结束线程方法(过时,不建议使用stop方法)
-
sleep(long millitime):让当前线程“睡眠”指定millitime睡眠,当前线程是堵塞状态
-
isalive:判断当前线程是否存活
-
线程的优先级:
-
MAX_PRIORITY:10
-
MIN _PRIORITY:1
-
NORM_PRIORITY:5
-
2.如何获取和设置当前线程的优先级
- 2.1getPriority() :返回线程优先值
- 2.2setPriority(int newPriority)改变线程的优先级
-
说明:线程创建时继承父线程的优先级 ,低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
-
*/
class helloThread extends Thread{
public helloThread(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
// try {
// sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() +Thread.currentThread().getPriority()+ “:” + i);
}
// if (i %20 == 0){
// yield();//this.yield()当前线程
// }
}
setPriority(1);
}
}
public class ThreadMethodTest {
public static void main(String[] args) throws InterruptedException {
helloThread helloThread = new helloThread(“线程一:”);
// helloThread.setName(“线程一”);
helloThread.setPriority(Thread.MAX_PRIORITY);//设置主线程的优先级
helloThread.start();
//给主线程命名
Thread.currentThread().setName(“主线程”);
for (int i = 0; i < 100; i++) {
if (i %2 == 0){System.out.println(Thread.currentThread().getName()+Thread.currentThread().getPriority()+":"+i); }
// if (i == 20){
// helloThread.join();
// }
}
System.out.println(helloThread.isAlive());
}
}
利用实现runable 接口的方式构造线程
package Thread;
/*
- 创建多线程的方拾贰:实现runnable接口
- 1.创建一个实现runnable接口的类
- 2.重写runnable接口的run()方法
- 3.创建实现类的对象
- 4.将此对象作为参数传递到thread类的构造器中,创建thread的对象
- 5.通过thread类的对象调用start()方法
- */
//创建接口的实现类
class MThread implements Runnable{
//重写run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i %2 == 0){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
//创建实现类的对象
MThread m1 = new MThread();
//将实现类的对象作为一个参数传递到thread方法构造器中
Thread t1 = new Thread(m1);//多态:编译看左,运行看右
t1.setName(“线程一:”);//设置线程的name
t1.setPriority(10);//设置线程优先级
t1.start();
//在启动一个线程,遍历100以内的偶数
Thread t2 = new Thread(m1);//多态:编译看左,运行看右
t2.setName(“线程二”);//设置线程的name
t2.setPriority(1);//设置线程优先级
t2.start();
}
}
两种方法解决同一个问题
继承thread类的
package test;
/*
- 例子:三个窗口卖票,总量为:100:使用继承thread类的范式
*存在线程安全问题 - */
public class WindowsTest {
public static void main(String[] args) {
windows windows1 = new windows();
windows windows2 = new windows();
windows windows3 = new windows();
windows1.setName(“窗口一”);
windows2.setName(“窗口二”);
windows3.setName(“窗口三”);
windows1.start();
windows2.start();
windows3.start();
//100 同步问题:线程安全问题
}
}
class windows extends Thread{
private static int ticket = 100;
@Override
public void run() {
while (true){
if (ticket >0){
System.out.println(getName()+ “: 卖票”+ticket);
ticket–;
}else {
break;
}
}
}
}
实现runable接口的
package test;
/*
-
例子:三个窗口卖票,总量为:100:使用实现runnable接口的范式
*存在线程安全问题 待解决 -
*/
class windows1 implements Runnable{
private int number = 100;
@Override
public void run() {
while (true){
if (number >0){
System.out.println(Thread.currentThread().getName()+“卖票:”+number);
number–;
}else{
break;
}}
}
}
public class WindowsTest1 {
public static void main(String[] args) {
windows1 w = new windows1();//只创建一个对象,只有100个票
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName(“窗口1”);
t2.setName(“窗口2”);
t3.setName(“窗口3”);t1.start(); t2.start(); t3.start();
}
}
两者的比较
比较继承和实现两者的比较
*开发中优先选择实现runable的接口的方式
- 1.实现的方式没有实现类的单继承性的局限性
- 2.实现的方式更适合处理多个线程共享数据的青睐
- 联系:
- thread类本身就是实现了runable接口的实现类
- 相同点:两种方式都需要重写run() 中,将线程要执行的逻辑声明在run()内。
生命周期
问题的原因
同步代码块解决实现类的线程安全问题
package test;
/*
-
例子:三个窗口卖票,总量为:100:使用实现runnable接口的范式
-
1.卖票过程中出现了重票、错票–>线程安全问题
-
2.问题出现的原因:
-
当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
-
3.如何解决?
-
当一个线程操作共享数据(number)的时候, 其他线程不能参与进来,直到线程a操作哦完成,其他线程才能参与进来
-
这种情况,即使线程a出现了阻塞也不能被改变。
-
4.在java中,我们通过这个同步机制,来解决安全问题
-
方式一:同步代码块
*关键字:synchronized(同步监视器){ -
//需要被同步的代码
-
}
-
说明:操作共享数据的代码,即为需要被同步的代码
-
共享数据:多个线程共同操作的变量,比如:number就是共享数据
-
3.同步监视器:锁,任何一个类的对象,都可以充当锁
-
要求:多个线程必须共用一个锁(也就是必须只能一个对象)
-
方法二:同步方法
-
5.同步的方式,解决了线程的安全问题。
-
操作同步代码时,只能有一个线程参与,相当于是一个单线程的过程。效率低–》局限性
*存在线程安全问题 待解决 -
*/
class windows1 implements Runnable{
private int number = 100;
//Object obj = new Object();
dog d1 = new dog();
@Override
public void run() {while (true){ synchronized (d1){ if (number >0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"卖票:"+number); number--; }else{ break; } } }
}
}
public class WindowsTest1 {
public static void main(String[] args) {
windows1 w = new windows1();//只创建一个对象,只有100个票
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName(“窗口1”);
t2.setName(“窗口2”);
t3.setName(“窗口3”);t1.start(); t2.start(); t3.start();
}
}
class dog {
}
同步代码块解决继承thread类的线程安全问题
package test;
/*
- 例子:三个窗口卖票,总量为:100:使用继承thread类的范式
*存在线程安全问题 - 使用同步代码块解决继承tread的线程安全问题
*说明:在继承thread的类创建多线程的方式中,慎用this充当同步监视器,当时可以用类来充当同步监视器
*
- 问题:多个线程必须共用同一把锁
- w
- */
public class WindowsTest {
public static void main(String[] args) {
windows windows1 = new windows();
windows windows2 = new windows();
windows windows3 = new windows();
windows1.setName(“窗口一”);
windows2.setName(“窗口二”);
windows3.setName(“窗口三”);
windows1.start();
windows2.start();
windows3.start();
//100 同步问题:线程安全问题
}
}
class windows extends Thread{
private static int ticket = 100;
private static Object object = new Object();
@Override
public void run() {
while (true){
synchronized (windows.class){//类也是对象 class,只会加载一次 (一个类)
//synchronized(object) {
//synchronized (this){错误的写法,因为继承new了三个对象,锁不唯一
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + “: 卖票” + ticket);
ticket–;
} else {
break;
}
}
}
}
}
同步方法解决实现runable接口的类的线程安全问题
package day020;
/**
-
使用同步方法解决runable接口的线程安全问题
*/
class windows3 implements Runnable {
private int number = 100;//Object obj = new Object();
//dog d1 = new dog();
@Override
public void run() {while (true) { //synchronized (this){//synchronized (d1){ //} //show(); if (number >0){ show(); }else { break; } }
}
private synchronized void show() {//默认的同步监视器:this
if (number > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + “卖票:” + number);
number–;
}
}
}
public class WindowsTest1 {
public static void main(String[] args) {
windows3 w = new windows3();//只创建一个对象,只有100个票
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName(“窗口1”);
t2.setName(“窗口2”);
t3.setName(“窗口3”);t1.start(); t2.start(); t3.start();
}
}
同步方法解决继承thread类的线程安全问题
package day020;
/**
*
*
*
-
关于同步方法的总结;
-
1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明
-
2.非静态的同步方法:监视器是;this :runable 实现类的线程安全问题
-
静态的同步方法:监视器是:当前类本身: 继承thread类的方法
-
@ Author :xiaopang
-
@ Date :Created in 18:13 2020/4/9
-
@ Description:用同步方法解决继承thread的线程安全问题
-
@ Modified By:
-
@Version: $
*/
public class windows4 {
public static void main(String[] args) {
windows5 windows1 = new windows5();
windows5 windows2 = new windows5();
windows5 windows3 = new windows5();
windows1.setName(“窗口一”);
windows2.setName(“窗口二”);
windows3.setName(“窗口三”);
windows1.start();
windows2.start();
windows3.start();
//100 同步问题:线程安全问题
}
}
class windows5 extends Thread {
private static int ticket = 100;
private static Object object = new Object();@Override
public void run() {
while (true) {
//synchronized (windows.class){//类也是对象 class,只会加载一次 (一个类)
//synchronized(object) {
//synchronized (this){错误的写法,因为继承new了三个对象,锁不唯一
show();} // }
}
private static synchronized void show() {//默认同步监视器:当前的类
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + “: 卖票” + ticket);
ticket–;
}
}
}
同步方法的总结
关于同步方法的总结;
- 1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明
- 2.非静态的同步方法:监视器是;this :runable 实现类的线程安全问题
- 静态的同步方法:监视器是:当前类本身: 继承thread类的方法
单例模式-懒汉式的线程安全问题
package day020;
/**
-
@ Author :xiaopang
-
@ Date :Created in 11:12 2020/4/10
-
@ Description:懒汉式线程安全问题
-
@ Modified By:
-
@Version: $
*/
//懒汉式单例模式
public class test {
public static void main(String[] args) {}
//私有化构造器
private test(){}
private static test t1 = null;
private static test getT1(){//默认同步监视器bank.class
//方式一:效率差
// synchronized (test.class) {
// if (t1 == null){
// t1 = new test();
// }
// return t1;
// }
//效率高
if (t1 == null) {
synchronized (test.class) {
if (t1 == null) {
t1 = new test();
}} } return t1;
}
}
package day020;
import java.util.concurrent.locks.ReentrantLock;
/**
- @ Author :xiaopang
- @ Date :Created in 11:46 2020/4/10
- @ Description:解决线程安全的lock方式
- @ Modified By:
- @Version: jdk5.0新增方法$
- 存在线程安全问题
*面试题 synchronized 和lock 的异同 - 同:都可以解决线程安全问题
- 异:synchronized :在执行完相应的同步代码块以后,会自动的释放同步监视器
-
lock:在执行完相应的同步代码块以后,需要手动启动同步(lock()),也需要手动的结束(unlock())
*/
class window implements Runnable{
private int ticket = 100;
//实例化一个lock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//调用lock()方法
lock.lock();
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+“卖票:票号为”+ticket);
ticket–;
}else{
break;
}
} finally {
//调用解锁的方法
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
window w1 = new window();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.setName(“窗口一”);
t2.setName(“窗口二”);
t3.setName(“窗口三”);
t1.start();
t2.start();
t3.start();
}
}
线程通信
package day020;
/**
-
线程通信;交互打印100 (两个线程)
-
涉及到的三个方法;
-
wait():一旦执行此方法,当前线程就进入了阻塞状态,并释放同步监视器
-
notify():一旦执行此方法,就会唤醒被wait()的一个线程,如果有多个线程,只能唤醒其中一个线程
-
notifyall():一旦执行此方法,就会唤醒被wait()阻塞的所有线程
-
说明: 都必须在同步代码块中 wait() notify() notifyall 必须使用在同比代码块或者同步方法中。
-
wait() notify() notifyall 三个方法的调用者必须是同步代码块 或同步方法的同一个同步监视器(就是同一个对象)
-
wait() notify() notifyall 定义在object类中,是为了让所有的object的子类能够用线程通信
-
面试题:sleep() 和 wait() 的异同?
-
同:sleep()和wait() 都会是当前线程进入到阻塞状态
-
异:sleep 是thread类中声明的方法
-
wait是object类中声明的方法
-
sleep可以在任何需要的场景下使用,wait必须使用在同步代码块或者同步方法中调用
-
在同步代码块或同步方法中:
- sleep()不会释放锁
- 而 wait()会释放锁
-
@ Author :xiaopang
-
@ Date :Created in 13:12 2020/4/10
-
@ Description:线程通信测试
-
@ Modified By:
-
@Version: $
*/
class number implements Runnable{
private int number = 1;
private Object obj =new Object();
@Override
public void run() {
while (true){
synchronized (obj) {
obj.notify();//两个线程 唤醒一个线程
// notifyAll();//唤醒两个以上线程
if (number <=100){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+number);
number++;
try {
obj.wait();//使用wait()方法使得线程进入阻塞状态 会释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
}
}
}
public class test1 {
public static void main(String[] args) {
number n1 = new number();
Thread t1 = new Thread(n1);
Thread t2 = new Thread(n1);
t1.setName(“线程一”);
t2.setName(“线程二”);
t1.start();
t2.start();}
}
package test;
/**
- @ Author :xiaopang
- @ Date :Created in 13:37 2020/4/10
- @ Description:练习
- @ Modified By:
- @Version: $
*生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处 - 取走产品,店员一次只能持有固定数量的产品(比如:20),
- 如果生产者试图 生产更多的产品,店员会叫生产者停一下,
- 如果店中有空位放产品了再通 知生产者继续生产;如果店中没有产品了,
- 店员会告诉消费者等一下,如 果店中有产品了再通知消费者来取走产品。
*分析:是否是多线程的问题?是,生产者线程、消费者线程。 - 2.是否有共享数据的问题? 是、产品、店员
- 3.是否有线程安全问题?有
- 如何解决线程安全问题? 同步机制
*4.是否涉及到线程通信? 是 wait() notify()
*/
class Customer extends thread{//消费者
private Clerk clerk;
public Customer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName() +":开始消费产品");
while (true){
try {
thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.consumproduct();
}
}
}
class Productor extends thread{//生产者
private Clerk clerk;
private int number;
public Productor(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName() +":开始生产产品");
while (true){
try {
thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.product();
}
}
}
class Clerk{
private int productnumber = 0;
//生产产品
public synchronized void product() {
if (productnumber <20){
productnumber++;
System.out.println(thread.currentThread().getName()+":开始生产第"+productnumber+"产品");
notify();
}else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}//店员
//消费产品
public synchronized void consumproduct() {
if (productnumber >0){
System.out.println(thread.currentThread().getName()+":开始消费第"+productnumber+"产品");
productnumber--;
notify();
}else{
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Productor p1 = new Productor(clerk);
p1.setName(“生产者1”);
Customer c1 = new Customer(clerk);
c1.setName(“消费者1”);
Customer c2 = new Customer(clerk);
c2.setName(“消费者二”);
c2.start();
p1.start();
c1.start();
}
}
实现callable 接口创建多线程
package day020;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
- @ Author :xiaopang
- @ Date :Created in 14:06 2020/4/10
- @ Description:新增线程创建方式
- @ Modified By:
- @Version: $
- 创建线程的实现方式三:实现callable接口—》jdk5.0以后
- 如何理解callable实现接口创建多线程比实现runable接口创建多线程强大?
- 1.call()方法可以有返回值
- 2.call()方法可以抛出异常,被外面的操作捕获
- 3.call()支持泛型
*/
public class CallableTest {
public static void main(String[] args) {
//4.创建callable实现类的对象
call c1 = new call();
//5.将此实现类的对象作为参数传递到futuretask的构造器中,创建对象
FutureTask f1 = new FutureTask(c1);
Object sum = null;
//6.将futuretask的对象作为参数传递到thread类的构造器中,创建thread的 的对象,并启动start方法
Thread thread = new Thread(f1);
thread.start();
try {//7.获取callable中的call方法的返回值
sum = f1.get();//get的返回值即为FutureTask的构造器参数callable实现类重写的call方法的返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(sum);
}
}
//1.创建一个实现callable的实现类
class call implements Callable{
//2.重写call方法,call方法有返回值
@Override
public Object call() throws Exception {//3.将线程要执行的代码写在call方法中
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i %2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;
}
}
实现线程池
package day020;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
- @ Author :xiaopang
- @ Date :Created in 14:38 2020/4/10
- @ Description:线程池
- @ Modified By:
- @Version: $
*提高响应速度(减少了创建新线程的时间) - 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理
- corePoolSize:核心池的大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终止 …
*/
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 ThreadPool {
public static void main(String[] args) {
//提供指定数量的线程数量的线程池
ExecutorService servixe = Executors.newFixedThreadPool(10);
//执行指定的线程的操作,需要提供runable和callable的实现类的对象
//设置线程池的属性
ThreadPoolExecutor service1 = (ThreadPoolExecutor)servixe;
System.out.println(servixe.getClass());
servixe.execute(new numberthread());//适合适用于runable
// servixe.submit();//适合适用于callable
//关闭线程池
servixe.shutdown();
}
}