新手初学Java网络编程


Posted in Java/Android onJuly 07, 2021
目录
  • 运行线程
    • 回调
    • 同步方法
    • 同步块
    • 死锁
    • 优先级
    • 暂停
      • 可以对IO阻塞
      • 可以对同步对象阻塞
      • 可以放弃
      • 可以休眠
      • 可以连接另一个线程
      • 可以等待一个对象
      • 可以结束
    • 可以被更高优先级线程抢占
  • 总结

 

运行线程

创建Thread的子类

public class ThreadChild extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        ThreadChild t = new ThreadChild();
        t.start();
    }
}

创建Thread传入Runnable接口实现类

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new RunnableImpl());
        t.start();
    }
}

 

回调

ExecutorService线程池的Submit()可接收Runnable或者Callable.Callable执行结束后有返回值,Runnable执行结束后没有返回值.可以通过submit的返回对象Future的get方法获取返回返回值,需要注意的是get方法是一个阻塞方法.若线程没有执行完毕,则会阻塞get()直到线程执行结束后返回数据.

public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(() -> {
            TimeUnit.SECONDS.sleep( 3);
            return 1;
        });
        Future<?> future2 = executorService.submit(() -> {
        });
        Future<String> future3 = executorService.submit(() -> {
        }, "aaa");
        System.out.println(future.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

 

同步方法

synchronized关键字和方法组合使用后,该方法是一个同步方法。同步方法都有一个隐试的锁,多个线程同时执行该方法时,只能顺序执行,未强到锁的线程处于阻塞状态。另外静态方法和非静态方法使用的是不同的锁,非静态方法的锁是对象锁,若两个线程通过两个该类的对象调用那么互不影响。静态方法是类锁,即本类的Class对象。同步方法无法指定锁资源,要么是this锁,要么是Class锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        Thread t1 = new Thread(()->{
            test.synFunction();
        });
        Thread t2 = new Thread(()->{
            test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            Test.synFunction();
        });
        Thread t2 = new Thread(()->{
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}

 

同步块

同步代码块可以指定锁对象,非静态方法可以指定任意的对象锁,或者任意的类锁。但静态方法只能使用任意的类锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test lock = new Test();
        Thread t1 = new Thread(() -> {
            lock.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (this) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction(lock1);
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction(lock2);
        });
        t1.start();
        t2.start();
    }
    public void synFunction(Object lock) {
        synchronized (lock) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (Test.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction();
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction() {
        synchronized (Object.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}

 

死锁

当多个线程竞争锁时,可能会导致死锁。一个线程由于没有得到一个锁而阻塞它也不会释放已经获取的锁。方法1获取锁的顺序是Test.class,Object.class。方法2获取锁的顺序是Object.class,Test.class。程序会陷入死锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction1();
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction2();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction1() {
        synchronized (Test.class) {// 类锁
            try {
                System.out.println("synFunction1-------------AAAAAAAAAAAAA");
                synchronized (Object.class) {// 类锁
                    try {
                        System.out.println("synFunction1-------------bbbbbbbbbbbbb");
                    } catch (Exception e) {
                    }
                }
            } catch (Exception e) {
            }
        }    
    }
    public static void synFunction2() {
        synchronized (Object.class) {// 类锁
            try {
                System.out.println("synFunction2-------------AAAAAAAAAAAAA");
            } catch (Exception e) {
            }
            synchronized (Test.class) {// 类锁
                try {
                    System.out.println("synFunction2-------------bbbbbbbbbbbbb");
                } catch (Exception e) {
                }
            }
        }
    }
}

 

优先级

不是所有线程创建时都是均等的,每个线程都有一个优先级,指定从0-10的整数。当多个线程运行时,虚拟机通常只运行最高优先级的线程,但这并不是一个严格的规则。在Java中10是最高优先级,0是最低优先级。默认优先级为5.并不是所有操作系统都支持这11个优先级。例如Windows只有7个优先级。优先级(1,2)(3,4)(6,7)(8,9)会做同样的处理。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction("bbbbbbbbbb");
        });
        t2.setPriority(9);
        t1.setPriority(1);
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        System.out.println(name+"--------------");
    }
}

 

暂停

为了能让其他线程有机会运行,一个线程有8中方式可以暂停或者指示它准备暂停。

 

可以对IO阻塞

要让网络程序中的线程自动放弃CPU控制权,最常见的方式是IO阻塞。由于CPU比网络和磁盘快的多,网络程序经常会在等待数据从网络到达或向网络发送数据时阻塞。即使只阻塞几毫秒,这一点时间也足够其他线程用来完成重要的任务。

 

可以对同步对象阻塞

线程在进入一个同步方法或代码块时也会阻塞。如果这个线程没有所同步对象的锁,而其他线程拥有这个锁,这个线程就会暂停,直到锁被释放为止。如果这个锁永远不会释放,那么这个线程会永久停止。

 

可以放弃

调用Thread.yield()静态方法可以做到显试的放弃线程控制权,这将通知虚拟机,可以优先执行其他线程。放弃并不会释放这个线程拥有的锁,因此在理想情况下被放弃的线程不要做任何的同步。如果等待运行的其他线程都是因为这个线程所拥有的同步资源而阻塞,那么这些线程将不能运行。实际上,控制权将回到唯一可以运行的线程,即刚刚放弃的这个线程,这很大程度上失去了放弃的意义。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        for (int i = 0;; i++) {
            Thread.yield();
            System.out.println(name + "--------------" + i);
        }
    }
    public static void synFunction2(String name) {
        for (int i = 0;; i++)
            System.out.println(name + "--------------"+i);
    }
}

 

可以休眠

休眠是更有利的放弃方式。放弃只是表示线程愿意暂停,让其他有相同优先级的线程有机会运行,而进入休眠的线程有所不同,不管有没有其他线程准备运行,休眠线程都会暂停。这样一来,不只是其他有相同优先级的线程会得到机会,还会给较低优先级的线程运行机会。不过进入休眠的线程仍然拥有它已经获得得所有锁。因此其他需要相同锁得线程依然会阻塞,要避免在同步方法或块内让线程休眠。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 10);
        } catch (Exception e) {
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}
package com.datang.bingxiang.demo;
import java.util.concurrent.TimeUnit;
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 3, 999999);//3000毫秒+999999毫秒(第二个参数不能超过999999,也就是不能超过1毫秒)
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}

 

可以连接另一个线程

连接线程(既调用join()方法得线程A)等待被连接的线程(join()方法所属的线程对象B)执行完毕后才会执行。在A线程调用B线程的join()A线程会等待B线程执行结束后才会继续执行。要注意的是A线程并不会释放已经获取的锁资源。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa",t2);
        });
        
        t1.start();
        t2.start();
    }
    public  static void synFunction(String name,Thread t) {
        try {
            t.join();
            //t.join(1000);
            //t.join(1000,999999);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
    public  static void synFunction2(String name) {
        try {
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
}

 

可以等待一个对象

线程可以等待一个它锁定的对象.在等待时,它会释放这个对象的锁并暂停,直到它得到其他线程的通知.另一个线程以某种方式修改这个对象,通知等待对象的线程,然后继续执行.等待会暂停执行,直到一个对象或资源到达某种状态.实际上,要等待某个特定的对象,希望暂停的线程首先必须使用synchronized获得这个对象的锁,然后调用这个对象的三个重载wait()方法之一.

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        Thread t1 = new Thread(() -> {
            d.a();
        });
        Thread t2 = new Thread(() -> {
            d.b();
        });
        t1.start();
        t2.start();
    }
    boolean flag = true;
    public synchronized void a() {
        try {
            while (true) {
                if (flag) {
                    System.out.println("执行AAAAAAAAAAA");
                    flag = false;
                } else {
                    wait();//等待,不限制等待时间
                    //wait(1000);//等待指定的时间,没有被notify唤醒也可以自己退出等待
                    //wait(1000,999999);//毫秒+纳秒的等待时间
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
    public synchronized void b() {
        try {
            while (true) {
                if (!flag) {
                    System.out.println("执行BBBBBBBBBBB");
                    flag = true;
                } else {
                    wait();
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
}

 

可以结束

线程要以合理的方式放弃CPU控制权,一种方式是结束.当run()方法返回线程时,线程将撤销,其他线程可以接管CPU.在网络应用程序中,包装一个阻塞操作的线程往往会这么做,例如线程从服务器下载一个文件,这样应用程序的其他部分就不会被阻塞.另一方面,如果run()方法太简单,总是很快结束,而不会紫色,那就存在一个很实际的问题:到底有没有必要生成一个线程.虚拟机在建立和撤销线程时会有很大的开销.如果线程会在极端的时间内结束,那么使用一次简单的方法调用而不是单独的线程可能会结束的更快.

 

可以被更高优先级线程抢占

Thread的setPriority(int priority)设置线程的优先级.

 

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Java/Android 相关文章推荐
详解Java实践之建造者模式
Jun 18 Java/Android
详解Java实现设计模式之责任链模式
Jun 23 Java/Android
Java基础之详解HashSet的使用方法
Jun 30 Java/Android
springboot项目以jar包运行的操作方法
Jun 30 Java/Android
Java实现聊天机器人完善版
Jul 04 Java/Android
SpringBoot整合Mybatis Generator自动生成代码
Aug 23 Java/Android
Java实现房屋出租系统详解
Oct 05 Java/Android
Java中try catch处理异常示例
Dec 06 Java/Android
mybatis源码解读之executor包语句处理功能
Feb 15 Java/Android
SpringBoot中获取profile的方法详解
Apr 08 Java/Android
零基础学java之循环语句的使用
Apr 10 Java/Android
Springboot-cli 开发脚手架,权限认证,附demo演示
Apr 28 Java/Android
Java 语言中Object 类和System 类详解
Jul 07 #Java/Android
新手初学Java List 接口
Jul 07 #Java/Android
Spring Boot 整合 Apache Dubbo的示例代码
Jul 04 #Java/Android
Java实现聊天机器人完善版
JavaGUI模仿QQ聊天功能完整版
JavaWeb Servlet实现网页登录功能
swagger如何返回map字段注释
You might like
浅析SVN常见问题及解决方法
2013/06/21 PHP
THINKPHP项目开发中的日志记录实例分析
2014/12/01 PHP
php指定长度分割字符串str_split函数用法示例
2017/01/30 PHP
php实现文件管理与基础功能操作
2017/03/21 PHP
jquery 简单图片导航插件jquery.imgNav.js
2010/03/17 Javascript
jQuery下通过$.browser来判断浏览器.
2011/04/05 Javascript
jQuery中的.bind()、.live()和.delegate()之间区别分析
2011/06/08 Javascript
jQuery简单实现上下,左右滑动的方法
2016/06/01 Javascript
JavaScript制作简单分页插件
2016/09/11 Javascript
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
2017/03/28 NodeJs
javascript 数据存储的常用函数总结
2017/06/01 Javascript
微信小程序 空白页重定向解决办法
2017/06/27 Javascript
AngularJS中使用three.js的实例详解
2017/07/21 Javascript
新版小程序登录授权的方法
2018/12/12 Javascript
微信小程序HTTP接口请求封装代码实例
2019/09/05 Javascript
超简单的微信小程序轮播图
2019/11/22 Javascript
Node.js Domain 模块实例详解
2020/03/18 Javascript
Element Rate 评分的使用方法
2020/07/27 Javascript
Python创建系统目录的方法
2015/03/11 Python
实例讲解Python中函数的调用与定义
2016/03/14 Python
Flask框架信号用法实例分析
2018/07/24 Python
一文带你了解Python中的字符串是什么
2018/11/20 Python
python网络编程 使用UDP、TCP协议收发信息详解
2019/08/29 Python
Python高级编程之继承问题详解(super与mro)
2019/11/19 Python
Python中正则表达式对单个字符,多个字符和匹配边界等使用
2021/01/27 Python
KELLER SPORTS荷兰:在线订购最好的运动产品
2020/10/13 全球购物
娇韵诗香港官网:Clarins香港
2020/08/13 全球购物
ajax是什么及其工作原理
2012/02/08 面试题
建材业务员岗位职责
2013/12/08 职场文书
报关专员求职信范文
2014/02/22 职场文书
连带责任保证书
2014/04/29 职场文书
热门专业求职信
2014/05/24 职场文书
人力资源管理专业求职信
2014/07/23 职场文书
酒店端午节活动方案
2014/08/26 职场文书
新娘婚礼致辞
2015/07/27 职场文书
利用Apache Common将java对象池化的问题
2022/06/16 Servers