例子:单核CUP执行两件事,串行执行时间快,还是多线程执行快? 答:串行执行快。因为单核,执行的总时间一样,而多线程增加了线程切换的时间。
MyThread 继承Thread类,重写run方法,Thread.start()开启新线程,调用Thread.run方法,此时已重写,调用MyThread的run()方法。
//1.创建一个继承于Thread的子类
class MyThread extends Thread{
//2.重写Thread类的run方法
@Override
public void run() {
//打印10内偶数的操作
for (int i = 0; i < 10; i++) {
if (i % 2 == 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的偶数:"+i);
}
}
}
}
public class ThreadCreateTest {
public static void main(String[] args) {
//3.创建Thread类的子类的对象
MyThread t1 = new MyThread();
//4.通过此对象调用start对象
t1.start();
//打印10内奇数的操作
for (int i = 0; i < 10; i++) {
if (i % 2 != 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的奇数:"+i);
}
}
}
}
结果:
线程:Thread-0的偶数:0
线程:main的奇数:1
线程:Thread-0的偶数:2
线程:main的奇数:3
线程:Thread-0的偶数:4
线程:main的奇数:5
线程:main的奇数:7
线程:main的奇数:9
线程:Thread-0的偶数:6
线程:Thread-0的偶数:8
public class ThreadCreateTest {
public static void main(String[] args) {
//匿名内部类方式创建
new Thread(){
@Override
public void run() {
System.out.println("方式一");
}
}.start();
//Lambda表达式方式
new Thread(() -> {
System.out.println("方式二");
}).start();
}
}
Thread类实现了Runable函数式接口如下,故创建Thread类也就是实现Runnable的run方法。
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
class MyThread2 extends Thread{
@Override
public void run() {
Thread.currentThread().setName("分线程");
String name = Thread.currentThread().getName();
String name1 = this.getName();
System.out.println(name);//结果:“分线程” 线程名字已修改
System.out.println(name == name1);//结果:true Thread.currentThread() 就是 this
}
}
public class ThreadCreateTest2 {
public static void main(String[] args) {
MyThread2 t2 = new MyThread2();
t2.start();
}
}
class MyThread3 extends Thread{
@Override
public void run() {
//打印100内偶数的操作
for (int i = 0; i < 10; i++) {
if (i % 2 == 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的偶数:"+i);
}
if(i == 4){
System.out.println("释放当前cup执行权");
Thread.yield();
}
}
}
}
public class ThreadCreateTest3 {
public static void main(String[] args) {
MyThread3 t3 = new MyThread3();
t3.start();
for (int i = 0; i < 10; i++) {
if (i % 2 != 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的奇数:"+i);
}
}
}
}
结果:
线程:Thread-0的偶数:0
线程:main的奇数:1
线程:Thread-0的偶数:2
线程:main的奇数:3
线程:Thread-0的偶数:4
释放当前cup执行权
线程:main的奇数:5
线程:main的奇数:7
线程:Thread-0的偶数:6
线程:main的奇数:9
线程:Thread-0的偶数:8
class MyThread4 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的偶数:"+i);
}
}
}
}
public class ThreadCreateTest4 {
public static void main(String[] args) throws InterruptedException {
MyThread4 t4 = new MyThread4();
t4.start();
for (int i = 0; i < 10; i++) {
if (i % 2 != 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的奇数:"+i);
}
if(i == 3){
t4.join();
}
}
}
}
结果:
线程:main的奇数:1
线程:Thread-0的偶数:0
线程:main的奇数:3
线程:Thread-0的偶数:2
线程:Thread-0的偶数:4
线程:Thread-0的偶数:6
线程:Thread-0的偶数:8
线程:main的奇数:5
线程:main的奇数:7
线程:main的奇数:9
class MyThread4 extends Thread{
@Override
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread5 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的偶数:"+i);
}
}
}
}
public class ThreadCreateTest5 {
public static void main(String[] args) throws InterruptedException {
MyThread5 t1 = new MyThread5();
t1.setPriority(10);
MyThread5 t2 = new MyThread5();
System.out.println("线程:"+t1.getName()+"优先级等级为:"+t1.getPriority());
System.out.println("线程:"+t2.getName()+"优先级等级为:"+t2.getPriority());
t1.start();
t2.start();
}
}
结果:
线程:Thread-0优先级等级为:10
线程:Thread-1优先级等级为:5
线程:Thread-0的偶数:0
线程:Thread-0的偶数:2
线程:Thread-1的偶数:0
线程:Thread-0的偶数:4
线程:Thread-1的偶数:2
线程:Thread-0的偶数:6
线程:Thread-1的偶数:4
线程:Thread-0的偶数:8
线程:Thread-1的偶数:6
线程:Thread-1的偶数:8
//1、创建实现Runnable接口的类
class MyRunnable implements Runnable{
//2.实现类去实现Runnable接口的抽象方法run
@Override
public void run() {
//打印100内偶数的操作
for (int i = 0; i < 10; i++) {
if (i % 2 == 0){
System.out.println("线程:"+Thread.currentThread().getName()+"的偶数:"+i);
}
}
}
}
public class RunnableCreateTest {
public static void main(String[] args) {
//3.创建实现类的对象
MyRunnable myRunnable = new MyRunnable();
//4.将对象传入Thread类构造方法
Thread t1 = new Thread(myRunnable);
t1.start();
}
}
创建Thread传入Runnable实例(其实现接口子类,多态),初始化target。Thread调用start本质还是调用实现接口的MyRunnable的run方法
private Runnable target;
public Thread(Runnable target) {
this(null, target, "Thread-" + nextThreadNum(), 0);
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
举个卖票栗子:
class TicketsRunnable implements Runnable{
private int ticket = 10;
@Override
public void run() {
while (true){
if(ticket > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖出票号:"+ticket);
}else {
break;
}
ticket--;
}
}
}
public class SellingTicketsTest {
public static void main(String[] args) {
TicketsRunnable runnable = new TicketsRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
Thread t3 = new Thread(runnable);
Thread t4 = new Thread(runnable);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
结果:
窗口1:卖出票号:10
窗口4:卖出票号:10
窗口3:卖出票号:10
窗口2:卖出票号:10
窗口2:卖出票号:6
窗口4:卖出票号:6
窗口3:卖出票号:6
窗口1:卖出票号:5
窗口2:卖出票号:2
窗口4:卖出票号:2
窗口1:卖出票号:2
窗口3:卖出票号:2
窗口2:卖出票号:-2
说明:run方法中睡眠了1秒,四个线程开启后,因为运行速度快,四个线程会依次进入睡眠,然后再票号-1前同时打印售出票10号,所以都是10。当票号还有2张时候,四个线程同上依次进入睡眠,然后同时打印出票2号,然后一个线程-1,票号为1,会进入下一次循环。同时其他三个线程-1,这时候票号为-2,这三个线程根据票号>0,也进入不了循环。那个进入循环的打印票号-2。
synchronized(同步监视器){ //需要被同步的代码 }
class TicketsRunnable implements Runnable{
private int ticket = 10;
final Object obj = new Object();
@Override
public void run() {
while (true){
//方式一:TicketsRunnable 只创建了一次,故obj对象只有一个
// synchronized (obj){
//方式二:TicketsRunnable.class 为 Class对象,只有一个
// synchronized (TicketsRunnable.class){
//方式三:TicketsRunnable 只创建了一次,故TicketsRunnable的对象也只有一个,this也只有一个
synchronized (this){
if(ticket > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖出票号:"+ticket);
}else {
break;
}
ticket--;
}
}
}
}
public class SellingTicketsTest {
public static void main(String[] args) {
TicketsRunnable runnable = new TicketsRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
Thread t3 = new Thread(runnable);
Thread t4 = new Thread(runnable);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
结果:
窗口1:卖出票号:10
窗口1:卖出票号:9
窗口1:卖出票号:8
窗口1:卖出票号:7
窗口1:卖出票号:6
窗口1:卖出票号:5
窗口1:卖出票号:4
窗口3:卖出票号:3
窗口3:卖出票号:2
窗口4:卖出票号:1
如果操作共享数据的代码完整的声明在一个方法中,可以将此方法声明为同步的。
实现Runnable接口:
class TicketsRunnable implements Runnable{
private int ticket = 10;
@Override
public void run() {
while (true){
show();
if (ticket < 0) {
break;
}
}
}
private synchronized void show(){//同步监视器:this
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + ":卖出票号:"+ticket);
}
ticket--;
}
}
public class SellingTicketsTest {
public static void main(String[] args) {
TicketsRunnable runnable = new TicketsRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
Thread t3 = new Thread(runnable);
Thread t4 = new Thread(runnable);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
继承Thread类:
class TicketsThread extends Thread{
private static int ticket = 10;//静态,创建多个TicketsThread对象,其只有一个共享
@Override
public void run() {
while (true){
show();
if (ticket < 0) {
break;
}
}
}
private static synchronized void show(){//同步监视器:TicketsThread类本身及Class对象,唯一的
if(ticket > 0){
System.out.println(Thread.currentThread().getName() + ":卖出票号:"+ticket);
}
ticket--;
}
}
public class SellingTicketsTest1 {
public static void main(String[] args) {
TicketsThread t1 = new TicketsThread();
TicketsThread t2 = new TicketsThread();
TicketsThread t3 = new TicketsThread();
TicketsThread t4 = new TicketsThread();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
总结:
public class Deadlock {
public static void main(String[] args) {
StringBuilder s1 = new StringBuilder("a");
StringBuilder s2 = new StringBuilder("1");
//线程一:
new Thread(){
@Override
public void run() {
synchronized (s1){
s1.append("b");
s2.append("2");
System.out.println("s1外: s1="+s1+"-----s2="+s2);
synchronized (s2){
s1.append("c");
s2.append("3");
System.out.println("s2内: s1="+s1+"-----s2="+s2);
}
}
}
}.start();
//线程二:
new Thread(() -> {
synchronized (s2){
s1.append("b");
s2.append("2");
System.out.println("s2外: s1="+s1+"-----s2="+s2);
synchronized (s1){
s1.append("c");
s2.append("3");
System.out.println("s1内: s1="+s1+"-----s2="+s2);
}
}
}).start();
}
}
结果:
s2外: s1=abb-----s2=122
s1外: s1=abb-----s2=122
两个线程都进入不到内层同步代码块中,因为此时双方拿着对方需要的锁(对象),等待对方释放,一直处于僵持阶段。
ReentrantLock lock = new ReentrantLock(true);//true为公平锁(线程先进来就先获取锁),默认false。
class LockRunnable implements Runnable{
private int tickets = 10;
//1.创建锁
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//2.调用锁定方法lock()
lock.lock();
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + " 售出票号:" + tickets);
tickets--;
} else {
break;
}
}finally {
//3.调用解锁方法unlock()
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
LockRunnable runnable = new LockRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.setName("窗口1");
t2.setName("窗口2");
t1.start();
t2.start();
}
}
结果:
窗口1 售出票号:10
窗口1 售出票号:9
窗口2 售出票号:8
窗口1 售出票号:7
窗口2 售出票号:6
窗口1 售出票号:5
窗口1 售出票号:4
窗口1 售出票号:3
窗口1 售出票号:2
窗口1 售出票号:1
synchronized 与 Lock的区别
使用两个线程打印1-10。线程1,线程2交替打印
class PrintRunnable implements Runnable{
private int num = 10;
@Override
public void run() {
while (true){
synchronized (this){
this.notify();
if (num > 0){
System.out.println(Thread.currentThread().getName() + ": 数字"+num);
num--;
}else {
break;
}
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class PrintThread {
public static void main(String[] args) {
PrintRunnable runnable = new PrintRunnable();
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
结果:
线程1: 数字10
线程2: 数字9
线程1: 数字8
线程2: 数字7
线程1: 数字6
线程2: 数字5
线程1: 数字4
线程2: 数字3
线程1: 数字2
线程2: 数字1
线程1进入同步代码块,通过notify方法,没有等待线程。直接打印,然后走到wait,阻塞,并释放锁。 线程2进入同步代码块,通过notify方法唤醒线程1,线程1处于就绪状态(锁在线程2手里)。直到线程2打印,然后走到wait,阻塞,释放锁,线程1开始接着wait后面继续执行。开始循环。 这样线程1、2就交替打印了。
//1.创建一个实现Callable的实现类
class CallableThread implements Callable<Integer>{
//2.实现call方法,将此线程需要执行的操作声明在call中
@Override
public Integer call() throws Exception {
int num = 0;
for (int i = 1; i <= 10; i++) {
num += i;
}
return num;
}
}
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//3.创建Callable接口实现类的对象
CallableThread callableThread = new CallableThread();
//4.将此Callable接口实现类的对象传入FutureTask的构造器中,创建FutureTask对象
FutureTask<Integer> futureTask = new FutureTask<>(callableThread);
//5.将Future对象传入Thread构造器中,创建此线程
Thread t1 = new Thread(futureTask);
t1.start();
//get返回值即为Callable实现类重写call方法的返回值(没有返回值则不调用)
Integer num = futureTask.get();
System.out.println(num);
}
}
class ThreadExecutor implements Runnable{
@Override
public void run() {
System.out.println("执行方法");
}
}
public class ThreadPool {
public static void main(String[] args) {
//1.提供指定线程数的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//设置属性
ThreadPoolExecutor poolExecutor = (ThreadPoolExecutor) service;
// poolExecutor.setCorePoolSize();
// poolExecutor.setMaximumPoolSize();
//2.执行指定的线程操作(Runnable)
service.execute(new ThreadExecutor());
// service.submit(Callable task)
//3.关闭连接池
service.shutdown();
}
}