victory的博客

长安一片月,万户捣衣声

0%

创建线程的三种方式

创建线程有三种方式,分别是继承Thread类、实现Runnable接口、实现Callable接口。

1.通过继承Thread类来创建并启动线程的步骤如下:
1.1定义Thread类的子类,并重写该类的run()方法,该run()方法将作为线程执行体。
1.2创建Thread子类的实例,即创建了线程对象。
1.3调用线程对象的start()方法来启动该线程。
2.通过实现Runnable接口来创建并启动线程的步骤如下:
2.1定义Runnable接口的实现类,并实现该接口的run()方法,该run()方法将作为线程执行体。
2.2创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread对象为线程对象。
2.3调用线程对象的start()方法来启动该线程。
3.通过实现Callable接口来创建并启动线程的步骤如下:
3.1创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。然后再创建Callable实现类的实例。
3.2使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
3.3使用FutureTask对象作为Thread对象的target创建并启动新线程。
3.4调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

阅读全文 »

创建线程池的7种方式

import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolCreationTest {
    public static void fixedThreadPool(){
//        ExecutorService threadPool = Executors.newFixedThreadPool(2);
//        
//        Runnable runnable = new Runnable(){
//            @Override
//            public void run(){
//                System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
//            }
//        };
//        
//        Future<?> submit = threadPool.submit(runnable);
////        System.out.println(submit);
////        System.out.println(submit.isDone());
//        threadPool.execute(runnable);
//        threadPool.execute(runnable);
//        threadPool.execute(runnable);
        
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        for(int i = 0; i < 4; i++){
            threadPool.execute(() -> {
                System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            });
        }
    }
    
    public static void cachedThreadPool(){
        ExecutorService threadPool = Executors.newCachedThreadPool();
        for(int i=0;i<10;i++){
            threadPool.execute(() -> {
                System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            });
        }
    }
    
    public static void singleThreadPool(){
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        for(int i = 0; i < 10; i++){
            threadPool.execute(() -> {
                System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
            });
        }
    }
    
    public static void scheduledThreadPool(){
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
        System.out.println("添加任务,时间:"+new Date());
        threadPool.schedule(()->{
            System.out.println("任务被执行,时间:"+new Date());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 1, TimeUnit.SECONDS);
    }
    
    public static void singleThreadScheduledPool(){
        ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
        System.out.println("添加任务,时间:"+new Date());
        threadPool.schedule(()->{
            System.out.println("任务被执行,时间:"+new Date());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, 2, TimeUnit.SECONDS);
    }
    
    public static void workStealingPool(){
        ExecutorService threadPool = Executors.newWorkStealingPool();
        for(int i = 0; i < 10; i++){
            final int index = i;
            threadPool.execute(() ->{
                System.out.println(index + "被执行,线程名"+Thread.currentThread().getName());
            });
        }
        while(!threadPool.isTerminated()){
            
        }
    }
    
    //推荐使用
    //阿里巴巴开发手册:线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
    public static void myThreadPoolExecutor(){
        final int CORE_POOL_SIZE = 5;  
        final int MAX_POOL_SIZE = 10;
        final int QUEUE_CAPACITY = 100;
        final Long KEEP_ALIVE_TIME = 1L;
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy()
                );
        for(int i = 0; i < 10; i++){
            final int index = i;
            threadPool.execute(() -> {
                System.out.println(index+"被执行,线程名:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
    }
    
    
    public static void main(String[] args) {
        //fixedThreadPool();
        //cachedThreadPool();
        //singleThreadPool();
        //scheduledThreadPool();
        //singleThreadScheduledPool();
        //workStealingPool();
        myThreadPoolExecutor();
    }
}

ThreadLocal示例

ThreadLocal:
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的ThreadLocal类正是为了解决这样的问题。
ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来。他们可以使用 get() 和 set() 方法来获取默认值或将修改其值,从而避免了线程安全问题。

代码:

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalTest implements Runnable{

    //private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(()->new SimpleDateFormat("yyyyMMdd HHmm"));
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };
    
    @Override
    public void run() {
        System.out.println("Thread Name="+Thread.currentThread().getName()+" default formatter="+formatter.get().toPattern());
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        formatter.set(new SimpleDateFormat());
        System.out.println("Thread Name="+Thread.currentThread().getName()+" current formatter="+formatter.get().toPattern());
        
    }
    
    public static void main(String[] args) throws InterruptedException{
        ThreadLocalTest obj = new ThreadLocalTest();
        for(int i=0;i<10;i++){
            Thread t = new Thread(obj, ""+i);
            Thread.sleep(new Random().nextInt(1000));
            t.start();
        }
    }
    
}

参考资料

package SingletonTest;

class Singleton{
    private volatile static Singleton instance;
    
    private Singleton(){
        
    }
    
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class) {
                if(instance == null){
                    instance = new Singleton();
                }
                //instance = new Singleton();
            }
        }
        return instance;
    }
}

public class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println(Singleton.getInstance().hashCode());
    }
    
    public static void main(String[] args){
        MyThread[] myThread = new MyThread[10];
        for(int i=0;i<myThread.length;i++){
            myThread[i] = new MyThread();
        }
        
        for(int i=0;i<myThread.length;i++){
            myThread[i].start();
        }
    }
}

双重锁的运行结果:

1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522

去掉第二重锁的运行结果(产生了多例):

1700548907
1486202908
1486202908
1700548907
1486202908
1486202908
1700548907
1486202908
1486202908
1700548907

HashMap的七种遍历方式

参考资料

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class HashMapTraversalMethodsTest {
    public static void main(String[] args) {
        
        Map<Integer, String> map = new HashMap();
        map.put(1, "Java");
        map.put(2, "Python");
        map.put(3, "C");
        map.put(4, "C++");
        map.put(5, "JavaScript");
        
        //迭代器EntrySet(推荐使用)
//        Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
//        while(iterator.hasNext()){
//            Entry<Integer, String> entry = iterator.next();
//            System.out.println(entry.getKey());
//            System.out.println(entry.getValue());
//        }
        
        //迭代器KeySet
//        Iterator<Integer> iterator = map.keySet().iterator();
//        while(iterator.hasNext()){
//            Integer key = iterator.next();
//            System.out.println(key);
//            System.out.println(map.get(key));
//        }
        
        //ForEach EntrySet
//        for(Entry<Integer, String> entry:map.entrySet()){
//            System.out.println(entry.getKey());
//            System.out.println(entry.getValue());
//        }
        
        //ForEach KeySet
//        for(Integer key:map.keySet()){
//            System.out.println(key);
//            System.out.println(map.get(key));
//        }
        
        //Lambda
//        map.forEach((key, value) -> {
//            System.out.println(key);
//            System.out.println(value);
//        });
        
        //Streams API单线程
//        map.entrySet().stream().forEach((entry) -> {
//            System.out.println(entry.getKey());
//            System.out.println(entry.getValue());
//        });
        
        //Streams API多线程
        map.entrySet().parallelStream().forEach((entry) ->{
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        });
    }
}

批量删除

1.list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>展示员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
<script type="text/javascript" src="${pageContext.servletContext.contextPath}/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
    $(function(){
        $("#selectAll").click(function(){
            $("[name='eid']").prop("checked", $(this).prop("checked"));
        });
        
        $("#deleteMore").click(function(){
            $("form").attr("action", $(this).attr("href")).submit();
            return false;//关闭默认跳转
        });
    });
</script>
</head>
<body>
    <form method="post">
        <input type="hidden" name="_method" value="DELETE"/>
        <table>
            <tr>
                <th>
                    <input type="checkbox" id="selectAll">
                </th>
                <th>EID</th>
                <th>ENAME</th>
                <th>AGE</th>
                <th>SEX</th>
                <th>DEPARTMENTNAME</th>
                <th>OPTIONS</th>
            </tr>
            <c:forEach items="${empList}" var="emp">
                <tr>
                    <td>
                        <input type="checkbox" name="eid" value="${emp.eid}"/>
                    </td>
                    <td>${emp.eid}</td>
                    <td>${emp.ename}</td>
                    <td>${emp.age}</td>
                    <td>${emp.sex == 0 ? '女':'男'}</td>
                    <td>${emp.dept.dname}</td>
                    <td>
                        <a href="emp">删除</a>
                        <a href="${pageContext.servletContext.contextPath}/emp/${emp.eid}">修改</a>
                    </td>
                </tr>
            </c:forEach>
            <tr>
                <td colspan="10">
                    <a id="deleteMore" href="${pageContext.servletContext.contextPath}/emps">批量删除</a>&nbsp;
                    ${page}
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

2.EmpMapper.java

public interface EmpMapper {
    //获取所有的员工信息
    List<Emp> getAllEmp();
    
    ......
    
    void deleteMore(String eids);
}

3.EmpMapper.xml

<!-- void deleteMore(String eids); -->
<delete id="deleteMore">
    delete from emp where eid in (${value})
</delete>

4.EmpService.java

public interface EmpService {
    ......
    
    void deleteMore(String eids);
}

5.EmpServiceImpl.java

@Service
public class EmpServiceImpl implements EmpService{
    @Autowired
    private EmpMapper empMapper;
    
    ......

    @Override
    public void deleteMore(String eids) {
        // TODO Auto-generated method stub
        empMapper.deleteMore(eids);
    }
}

6.EmpController.java

@Controller
public class EmpController {

    @Autowired
    private EmpService service;
    
    ......
    
    @RequestMapping(value="/emps", method=RequestMethod.DELETE)
    public String deleteMore(String eid){
        //获取客户端name属性相同的多个元素的值,可以通过字符串直接获取,每个值以逗号分隔,也可以以数组直接获取
        System.out.println(eid);
        service.deleteMore(eid);
        return "redirect:/emps/1";
    }
}

修改员工信息

1.list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>展示员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
</head>
<body>
    <table>
        <tr>
            <th>EID</th>
            <th>ENAME</th>
            <th>AGE</th>
            <th>SEX</th>
            <th>DEPARTMENTNAME</th>
            <th>OPTIONS</th>
        </tr>
        <c:forEach items="${empList}" var="emp">
            <tr>
                <td>${emp.eid}</td>
                <td>${emp.ename}</td>
                <td>${emp.age}</td>
                <td>${emp.sex == 0 ? '女':'男'}</td>
                <td>${emp.dept.dname}</td>
                <td>
                    <a href="emp">删除</a>
                    <a href="${pageContext.servletContext.contextPath}/emp/${emp.eid}">修改</a>
                </td>
            </tr>
        </c:forEach>
        <tr>
            <td colspan="10">
                ${page}
            </td>
        </tr>
    </table>
</body>
</html>

2.update.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
</head>
<body>
    <form:form action="${pageContext.servletContext.contextPath}/emp" method="post" modelAttribute="emp">
        <input type="hidden" name="_method" value="PUT"/>
        <form:hidden path="eid"/>
        <table>
            <tr>
                <th colspan="2">UPDATE EMP INFO</th>
            </tr>
            <tr>
                <td>ENAME</td>
                <td>
                    <form:input path="ename"/>
                </td>
            </tr>
            <tr>
                <td>AGE</td>
                <td>
                    <form:input path="age"/>
                </td>
            </tr>
            <tr>
                <td>sex</td>
                <td>
                    <form:radiobuttons path="sex" items="${sex}"/>
                </td>
            </tr>
            <tr>
                <td>DEPARTMENT</td>
                <td>
                    <form:select path="dept.did" items="${deptList}" itemLabel="dname" itemValue="did"></form:select>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <input type="submit" value="修改" />
                </td>
            </tr>
        </table>
    </form:form>
</body>
</html>

3.EmpController.java

@Controller
public class EmpController {

    @Autowired
    private EmpService service;
    
    @RequestMapping(value="/emp/{eid}", method=RequestMethod.GET)
    public String toUpdate(@PathVariable("eid")String eid, Map<String, Object> map){
        //要修改的员工信息
        Emp emp = service.getEmpByEid(eid);
        
        //所有的部门信息
        List<Dept> deptList = service.getAllDept();
        
        //获取存储性别的map集合
        Map<String, String> sex = new HashMap<>();
        sex.put("0", "女");
        sex.put("1", "男");
        
        map.put("emp", emp);
        map.put("deptList", deptList);
        map.put("sex", sex);
        
        return "update";
    }
    
    @RequestMapping(value="/emp", method=RequestMethod.PUT)
    public String updateEmp(Emp emp){
        service.updateEmp(emp);
        return "redirect:/emps/1";
    }
}

4.EmpService.java

public interface EmpService {
    ......
    
    List<Dept> getAllDept();
}

5.EmpServiceImpl.java

@Service
public class EmpServiceImpl implements EmpService{
    @Autowired
    private EmpMapper empMapper;
    
    @Autowired
    private DeptMapper deptMapper;
    
    ......
    
    @Override
    public List<Dept> getAllDept() {
        // TODO Auto-generated method stub
        return deptMapper.getAllDept();
    }
}

反射

1.反射
运行时分析类并调用类中的属性和方法
2.反射的应用场景
(1)spring、springboot等框架的实现
(2)动态代理
(3)注解
3.反射的优缺点
3.1优点
(1)灵活
(2)不安全(比如无视泛型参数的安全检查)
3.2缺点
性能稍差
4.获取Class对象的四种方式
(1)类.class
(2)Class.forName(类的全限定名)
(3)Instance.getClass()
(4)xxxClassLoader.loadClass()

SSM整合步骤:

1.导入jar包
spring:
springMVC:
mybatis:
第三方支持:log4j,pageHelper,AspectJ,jackson,jstl

2.搭建springMVC
(1)web.xml
CharacterEncodingFilter:filter
HiddenHttpMethodFilter:filter
DispatcherServlet:servlet
(2)springMVC.xml
扫描控制层组件:context:component-scan
视图解析器:InternalResourceViewResolver
Default Servlet:mvc:default-servlet-handler/
MVC驱动:<mvc:annotation-driven />
可选:MultipartResolver,拦截器

阅读全文 »