WPF在样式定义和UI动画上面相对于以前的技术有了不少的提升,下面给出WPF技术实现钟表的效果: 1、Visual Studio新建一个WPF应用程序,命名为WpfClock,新建一个images文件夹,并准备一个钟表的背景图片和程序图标素材。 2、编辑MainWindow.xaml文件,对UI进行定制,代码如下(指针都是用Rectangle实现的,当然可以用图片代替):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<Window x:Class="WpfClock.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Margin="2" Height="327" Width="311" AllowsTransparency="True" WindowStyle="None" Background="Transparent" WindowStartupLocation="CenterScreen" Icon="images/clock.ico" ResizeMode="NoResize" Topmost="False" Opacity="1"> <Grid Width="300" Height="300" MouseLeftButtonDown="Grid_MouseLeftButtonDown"> <Image Source="images/backGround.png"></Image> <Label Name="lab商标" Foreground="White" Margin="0,0,0,211" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="Auto" Width="Auto" FontSize="13" >JackMoon</Label> <Label Name="lab创建时间" Foreground="White" Margin="0,91,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Height="Auto" Width="Auto">1987</Label> <!-- 秒针定义 --> <Rectangle Margin="150,0,149,150" Name="rectangleSecond" Stroke="White" Height="120" VerticalAlignment="Bottom" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="secondPointer" CenterX="0" CenterY="120" Angle="0" /> </Rectangle.RenderTransform> </Rectangle> <!-- --> <!-- 分钟定义 --> <Rectangle Margin="150,49,149,151" Name="rectangleMinute" Stroke="LightGreen" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="minutePointer" CenterX="0" CenterY="100" Angle="45" /> </Rectangle.RenderTransform> </Rectangle> <!-- --> <!-- 时针定义 --> <Rectangle Margin="150,80,149,150" Name="rectangleHour" Stroke="LightYellow" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="hourPointer" CenterX="0" CenterY="70" Angle="90" /> </Rectangle.RenderTransform> </Rectangle> <!----> <Label Content="08:08:08" FontSize="16" Foreground="White" Height="Auto" HorizontalAlignment="Center" Margin="114,0,113,86" Name="labTime" VerticalAlignment="Bottom" Width="Auto" /> </Grid> </Window> |
3、编辑MainWindow.xaml.CS文件,对后台逻辑进行定制,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfClock { using System.Threading; using System.Windows.Threading; /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { //计时器 System.Timers.Timer timer = new System.Timers.Timer(1000); public MainWindow() { InitializeComponent(); #region 初始化时间 secondPointer.Angle = DateTime.Now.Second * 6; minutePointer.Angle = DateTime.Now.Minute * 6; hourPointer.Angle = (DateTime.Now.Hour * 30) + (DateTime.Now.Minute * 0.5); this.labTime.Content = DateTime.Now.ToString("HH:mm:ss"); #endregion timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Enabled = true; } private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //进行拖放移动 this.DragMove(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //UI异步更新 this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { //秒针转动,秒针绕一圈360度,共60秒,所以1秒转动6度 secondPointer.Angle = DateTime.Now.Second * 6; //分针转动,分针绕一圈360度,共60分,所以1分转动6度 minutePointer.Angle = DateTime.Now.Minute * 6; //时针转动,时针绕一圈360度,共12时,所以1时转动30度。 //另外同一个小时内,随着分钟数的变化(绕一圈60分钟),时针也在缓慢变化(转动30度,30/60=0.5) hourPointer.Angle = (DateTime.Now.Hour * 30)+ (DateTime.Now.Minute * 0.5); //更新时间值 this.labTime.Content = DateTime.Now.ToString("HH:mm:ss"); })); } } } |
4、编译运行,如果运气不错的话,应该能显示如下效果: 5、总结 WPF可以用RotateTransform中的Angle进行旋转,可以指定中心点(CenterX,CenterY)
1 2 3 |
<Rectangle.RenderTransform> <RotateTransform x:Name="hourPointer" CenterX="0" CenterY="70" Angle="90" /> </Rectangle.RenderTransform> |
from:https://www.cnblogs.com/isaboy/p/wpfclock.html
View Details简介 但凡涉及到图形界面,往往的设计都是不支持或者不推荐使用多个线程操作界面内容.而且通常会有一个专门的线程调度器来处理任务线程和界面线程的问题.下面提供两个两个方案. 使用Dispatcher.BeginInvoke 这个方法简单暴力适合小工作量的修改一些界面内容.使用Dispatcher.BeginInvoke()会将代码安排为调度程序的一个任务. 步骤 使用Thread新建并开始一个线程 在新建的线程处理函数中需要修改界面的时候获取界面的dispatcher 使用Dispatcher的BeginInvoke方法指定一个线程优先级,和一个委托,这个委托时用于修改界面内容的 下面给出一部分代码
1 2 3 |
//新建线程 Thread thread = new Thread(UpdateTextRight); thread.Start(); |
下面是新线程中的方法
1 2 3 4 5 6 7 8 9 10 |
//这个事例刚好是先窗体类中定义的,所以获取Dispatcher变得比较方便,而且使用了匿名委托.在通常的代码中会把委托给分离出去比较好. private void UpdateTextRight() { this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) delegate() { txt.Text = "Here is some new text."; } ); } |
使用BackgroupWorker 这个类是专门用于简化Windows Form程序与线程相关的问题设计的,同样适用于WPF程序.适合于一个长期的后台进程,支持进度通知,取消支持,完成通知等功能. 使用方法也很简单,创建一个BackfruopWorker实例,它有几个事件. DoWork事件会在另外一个线程中执行,用RunWorkerAsync()启动.所以在这个事件中不要去处理修改界面的事情 RunWorkerCompleted事件,在DoWork事件返回时(正常或者异常返回),在图形的线程中执行,所以可以修改界面 ProgressChanged事件,使用ReportProgress()方法调用,同时是在图形界面的线程中执行,通常负责修改一下进度条什么的.而ReportProgress()方法,通常会在DoWork的事件中调用,然后给一个百分比的值.要使用这个功能,需要把WorkerReportsProgress属性设置成true 另外值得一说的是,要取消支持需要把WorkerSupportsCancellation属性设为true,使用CancelAsync()方法调用,但是这个调用不会终止进程,所以在DoWork事件中需要判断CancellationPending. 下面给出部分代码 创建BackgroundWorker实例
1 2 3 4 5 6 7 8 9 10 11 |
BackgroundWorker backgroundWorker; backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += backgroundWorker_DoWork; backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; //可以返回工作进度 backgroundWorker.WorkerReportsProgress = true; backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged; //允许取消 backgroundWorker.WorkerSupportsCancellation = true; |
开始执行DoWork
1 |
backgroundWorker.RunWorkerAsync(); |
DoWork事件范例,这个方法的内容是在另外一个线程,异步执行得
1 2 3 4 5 6 7 8 9 10 11 |
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { while(!backgroundWorker.CancellationPending) { //Do SomeThing //在合适的时候使用 //backgroundWorker.ReportProgress(i); //报告一下进度,其中i是0-100的整数 } //这里可以使用e.Result给一个返回值,如果有需要的话 } |
进度改变时的处理事件,也就是修改一下进度条什么的
1 2 3 4 |
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar.Value = e.ProgressPercentage; } |
完成事件我就不演示,下面是取消任务的方法
1 2 3 4 |
private void cmdCancel_Click(object sender, RoutedEventArgs e) { backgroundWorker.CancelAsync(); } |
https://www.cnblogs.com/atskyline/archive/2012/06/22/2558516.html
View Details问题分析 一般出现这种情况的都是apache/nginx配置出现问题 问题解决 nginx解决办法 在location里面加上 try_files $uri $uri/ /index.php?$query_string; 如果配置文件中存在 try_files $uri $uri/ =404;需要将它注释掉或者删掉,否则会报错 本人的nginx配置(我是在域名里面进行配置的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
server { listen 80; server_name www.onlinebook.com; root /home/developer/Desktop/www/laravel_book/public/; index index.html index.php index.htm; location / { #try_files $uri $uri/ =404; try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; # # # With php7.0-cgi alone: # fastcgi_pass 127.0.0.1:9000; # # With php7.0-fpm: fastcgi_pass unix:/run/php/php7.0-fpm.sock; } } |
from:http://blog.csdn.net/sunxiang_520/article/details/51633837
View DetailsKotlin 是一个基于 JVM 的新的编程语言,由 JetBrains 开发。 Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。 JetBrains,作为目前广受欢迎的Java IDE IntelliJ 的提供商,在 Apache 许可下已经开源其Kotlin 编程语言。 Kotlin已正式成为Android官方支持开发语言。
View Details这个问题似乎以前碰到过,不过记不太清了。 程序重新生成,提示错误:在证书存储区中找不到清单签名证书。 可能是之前部署的程序证书被我删掉了或是证书过期了,结果出现这个问题。解决方案如下: 方案1:右击项目属性—>签名—>为ClickOnce清单签名,将勾掉的选项去掉。 方案2:在签名中创建一个新的签名。 方案3:记事本打开相应的csproj文件,调整节点值。<SignManifests>true</SignManifests>将true修改为false。 以上解决方案任选其一,我选了方案一,简单嘛。重新生成,问题搞定! from:https://www.cnblogs.com/190196539/archive/2011/12/03/2272861.html
View Detailshttp://www.jbxue.com/article/5649.html 打开一个页面<?php phpinfo(); ?> 然后在游览器下运行:页面提示 No input file specified. FastCGI模式下访问php文件时,出现No input file specified.错误 查看access.log 发现是 404 打开一个页面<?php phpinfo(); ?> 然后在游览器下运行:页面提示 No input file specified. FastCGI模式下访问php文件时,出现No input file specified.错误 查看access.log 发现是 404 原因分析: 1、任何对.php文件的请求,都简单地交给php-cgi去处理,但没有验证该php文件是否存在。PHP文件不存在,没办法返回普通的404错误,它返回 一个404,并带上一句”No input file specified” 2、还可能跟 路径或者 权限有关系,或者SCRIPT_FILENAME 变量没有被正确的设置(这在nginx是最常见的原因) 1)如果html也出现404错误,那么就是document root 设置的有问题 2)检查脚本文件的权限, 可能PHP或者web server不能读取它 3)SCRIPT_FILENAME设置错误 网上的解决方法: 步骤一:修改nginx主配置文件nginx.conf 默认安装的nginx配置文件中定义fastcgi处是:fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; 可以将它改成: fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 必须保证 $document_root 在配置文件中,在astcgi_param SCRIPT_FILENAME前面被用到过一次, 后面有解释为什么。 步骤二:修改PHP的住配置文件php.ini 修改/etc/php5/cgi/php.ini中cgi.fix_pathinfo=1 这样也可让php-cgi正常使用SCRIPT_FILENAME这个变量 有人说,这样改也行 fastcgi_param SCRIPT_NAME /home/gavin/nginx/$fastcgi_script_name; 让我们看看PHP对这两个变量是怎么解释的吧 SCRIPT_NAME SCRIPT_FILENAME 据说,必须指定正确的SCRIPT_FILENAME, PHP-CGI会忽略SCRIPT_NAME(即使它的值设置的是正确的) 或者指定特殊的php.ini, 设置doc_root, discard path, fix pathinfo等等 script_filename 只是被用做一种快捷方式。 如果fix_pathinfo设置打开,init函数将它用来决定真实的路径 因为配置文件会改变 nginx的变量$fastcgi_script_name fastcgi_param SCRIPT_NAME /home/gavin/nginx/$fastcgi_script_name; fastcgi_param […]
View DetailsNginx Nginx有官方native build的32bit版本, 也有cygwin build的64bit版本, 出于稳定性的考虑, 还是选了官方的32bit. 解压, 本例中使用的路径是 C:\Servers\nginx-1.9.12 , 创建两个bat, 用于启动和关闭nginx: start_nginx.bat
1 2 3 4 |
@echo off set NGINX_HOME=C:\Servers\nginx-1.9.12 start /D %NGINX_HOME%\ %NGINX_HOME%\nginx.exe pause |
stop_nginx.bat
1 2 3 4 5 |
@echo off set NGINX_HOME=C:\Servers\nginx-1.9.12 cd %NGINX_HOME% nginx.exe -s quit pause |
PHP 选的版本是 7.0.4 64位 NTS(非线程安全) VC14, 本例中解压至目录 C:\Servers\php-7.0.4-nts-Win32-VC14-x64 , 使用php.ini-development 创建 php.ini, 修改以下几处, (参考 http://man.chinaunix.net/develop/php/php_manual_zh/html/ini.core.html )
1 2 3 4 5 6 7 8 9 10 11 |
date.timezone = Asia/Shanghai enable_dl = On #允许用户在运行时加载PHP扩展,即在脚本运行期间加载 cgi.force_redirect = 0 # 启用时, 防止任何人通过如 http://my.host/cgi-bin/php/secretdir/script.php 这样的 URL 直接调用 PHP。PHP 在此模式下只会解析已经通过了 web 服务器的重定向规则的 URL. 在大多数 web 服务器中以 CGI 方式运行 PHP 时很有必要用 cgi.force_redirect 提供安全。PHP 默认其为 On。可以将其关闭,但风险自担。注: Windows 用户:可以安全地在 IIS 之下将其关闭,事实上必须这么做。要在 OmniHTTPD 或 Xitami 之下使用也必须将其关闭。 cgi.fix_pathinfo=1 #1:PHP CGI 以 / 为分隔符号从后向前依次检查请求的路径, 对 CGI 提供了真正的 PATH_INFO/PATH_TRANSLATED 支持。以前 PHP 的行为是将 PATH_TRANSLATED 设为 SCRIPT_FILENAME,而不管 PATH_INFO 是什么。有关 PATH_INFO 的更多信息见 cgi 规格。将此值设为 1 将使 PHP CGI 修正其路径以遵守规格。设为 0 将使 PHP 的行为和从前一样。默认为零。用户应该修正其脚本使用 SCRIPT_FILENAME 而不是 PATH_TRANSLATED。 fastcgi.impersonate = 1 #IIS(在基于 WINNT 的操作系统上)中的 FastCGI 支持模仿客户端安全令牌的能力。这使得 IIS 能够定义运行时所基于的请求的安全上下文。Apache 中的 mod_fastcgi 不支持此特性(03/17/2002)。如果在 IIS 中运行则设为 1。默认为 0。 cgi.rfc2616_headers = 1 #指定 PHP 在发送 HTTP 响应代码时使用何种报头。如果设定为 0,PHP 发送一个 Status: 报头,Apache 和其它 web server 都支持。如果此选项设定为 1,PHP 将发送 RFC 2616 兼容的报头。除非你知道自己在做什么,否则保留其值为 0。 |
添加扩展, 修改以下几处
1 2 3 |
extension_dir = "./ext" # 指定win7下的扩展目录 # 并取消用到的扩展前面的注释 |
启动的命令是
1 |
C:\>Servers\php-7.0.4-nts-Win32-VC14-x64\php-cgi.exe -b 127.0.0.1:9000 |
如果需要后台启动PHP CGI, 使用vbs, 创建 startup.vbs
1 |
createobject("wscript.shell").run "c:\Servers\php-7.0.4-nts-Win32-VC14-x64\php-cgi.exe -b 127.0.0.1:9000",0,false |
停止PHP CGI, 创建shutdown.bat
1 2 3 |
@echo off taskkill /fi "imagename eq php-cgi.exe" pause |
Nginx 启用 PHP 修改nginx.conf
1 2 3 4 5 6 7 |
location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } |
重启nginx 注: PHP5.6及以下, 需要将mysql 的 libmysql.dll 拷贝至 C:\Windows\SysWOW64 PHP7貌似已经取消了支持,编译都没有了--with-mysql参数,只支持--with-mysqli和--with-pdo-mysql, 故libmysql.dll已经不需要 如果提示api-ms-win-crt-runtime-l1-1-0.dll丢失, 请安装 visual c++ redistributable 2015, 从微软官网上可以下载. 安装对系统的要求必须在win7 sp1以上, 如果win7还未升级的, 安装会失败. from:https://www.cnblogs.com/milton/p/5244387.html
View Details1、ArrarList 转换为 string[] ArrayList list = new ArrayList(); list.Add("aaa"); list.Add("bbb"); //转换成数组 string[] arrString = (string[])list.ToArray(typeof( string)); 2、string[] 转换为 ArrarList ArrayList list = new ArrayList(new string[] { "aaa", "bbb" }); 3、ArrayList 转换为 string ArrayList list = new ArrayList(); list.Add("aaa"); list.Add("bbb"); //转换成数组 string str= string.Join(",", (string[])list.ToArray(typeof( string))); 4、string 转换为 ArrayList string str="1,2,3,4,5"; ArrayList b = new ArrayList( str.Split(',') ); from:https://www.cnblogs.com/stone_w/archive/2012/03/21/2409357.html
View Details有关wordpress IP验证不当漏洞的通知,阿里云每天一封邮件加一条短信。虽然关系不大,但还是看着心烦。同时升级专业版不是小博客能够承受的,所以只能自己动手。 漏洞描述 wordpress /wp-includes/http.php文件中的wp_http_validate_url函数对输入IP验证不当,导致黑客可构造类似于012.10.10.10这样的畸形IP绕过验证,进行SSRF。【注意:该补丁为云盾自研代码修复方案,云盾会根据您当前代码是否符合云盾自研的修复模式进行检测,如果您自行采取了底层/框架统一修复、或者使用了其他的修复方案,可能会导致您虽然已经修复了改漏洞,云盾依然报告存在漏洞,遇到该情况可选择忽略该漏洞提示】 漏洞修复 找到wp-includes/http.php这个文件,在文件的465行附近找到:
1 |
$same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] ); |
把改行修改为成以下代码,或者注销该行添加。
1 2 3 4 5 |
if (isset($parsed_home['host'])) { $same_host = (strtolower($parsed_home['host']) === strtolower($parsed_url['host']) || 'localhost' === strtolower($parsed_url['host'])); } else { $same_host = false; }; |
还是这个文件,在 478行左右找以下代码
1 |
if ( 127 === $parts[0] || 10 === $parts[0] |
替换成
1 |
if ( 127 === $parts[0] || 10 === $parts[0] || 0 === $parts[0] |
如果在修改的时候发现478该行代码已经是修改过的代码,请忽略。 漏洞验证 登录阿里云帐号,在服务器安全页面点击验证。 参考连接: https://my.oschina.net/u/1433006/blog/752189 from:http://www.sijitao.net/2508.html
View Details目标:为提高数据库表更新(update)效率,使用多线程更新。其实这里也可以考虑另一种方法批量更新,不过如果更新失败了,同一事务(transaction)中的其他更新语句就会回滚,比较麻烦,所在还是简单点用多线程去处理。 困难点:开始是想把需要更新的数据等分到线程中去处理,不过搞了一段时间都没成功,主要是没有什么办法把动态参数从线程外传进线程内。后来换了个思路,每个线程去拿一条数据去更新,拿数据时同步处理。这样之后就可以了。 例子(部分外部类没有写上去,所以只能参考,要运行需要改改):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; public class BaiduBaikeJob { static final Logger logger = LoggerFactory .getLogger(BaiduBaikeJob.class); @Autowired private MongoLockService mongoLockService; @Autowired private WeiboPersonService weiboPersonService; @Resource(name = "globalProperties") private PropertyPlaceholderConfigurer config; final int THREAD_COUNT = 10; AtomicInteger updCounter = new AtomicInteger(0); AtomicInteger next = new AtomicInteger(0); private CountDownLatch threadCompletedCounter = new CountDownLatch(THREAD_COUNT); /** * 每隔 1小时,获得百度百科里的人物信息 */ public void baiduBaikeRun() { if ("true".equalsIgnoreCase((String) config.getProperty("runBaiduBaikeJob", "false")) && mongoLockService.getLock(MongoLockService.LOCK_BAIDU_BAIKE)) { List<WeiboPerson> unBaikeFills = null; try { unBaikeFills = weiboPersonService.findUnBaikeFills(2000); if (unBaikeFills != null && !unBaikeFills.isEmpty()) { List<WeiboPerson> weiboPersonList = new ArrayList<WeiboPerson>(); for (final WeiboPerson person : unBaikeFills) { // 获取百度百科信息 WeiboPerson weiboPerson = BaiduBaikeUtils.getBaiduBaikeInfo(person.getName()); weiboPerson.setId(person.getId()); weiboPerson.setName(person.getName()); weiboPerson.setTenantId(person.getTenantId()); weiboPerson.setGroupId(person.getGroupId()); // 更新状态 if (!StringUtils.isEmptyString(weiboPerson.getDescription())) { weiboPerson.setFlagBaike(WeiboPerson.BAIKE_SUCCESS); } else { weiboPerson.setFlagBaike(WeiboPerson.BAIKE_FAIL); } weiboPerson.setLastUpdDate(new Date()); weiboPersonList.add(weiboPerson); } // 首次更新或过期更新 baiduBaikeRunInMultiThreads(weiboPersonList); } } catch (Exception e) { logger.error("update baidu baike error," + e.getClass().getName() + ": " + e.getMessage()); } finally { try { mongoLockService.releaseLock(MongoLockService.LOCK_BAIDU_BAIKE); } catch (Exception e) { logger.error("release lock error ", e); } } } } /** * 多线程处理:更新table */ private void baiduBaikeRunInMultiThreads(final List<WeiboPerson> weiboPersonList) { ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); for (int i = 0; i < THREAD_COUNT; i++) { executor.submit(new Runnable() { public void run() { WeiboPerson weiboPerson = getNext(weiboPersonList); while (null != weiboPerson) { try { // 首次更新或过期更新 weiboPersonService.update(weiboPerson); } catch (Exception e) { logger.error("table weiboPerson update error ", e); } updCounter.incrementAndGet(); // System.out.println("Thread:" + Thread.currentThread().getName() + ", counter:" + updCounter + ", name:" + weiboPerson.getName()); weiboPerson = getNext(weiboPersonList); } threadCompletedCounter.countDown(); } }); } closeThreadPool(executor); } /** * 同步处理:获取需要更新的一条微博人物 */ private synchronized WeiboPerson getNext(List<WeiboPerson> weiboPersonList){ if(next.intValue()>=weiboPersonList.size()) return null; next.incrementAndGet(); return weiboPersonList.get(next.intValue()-1); } /** * 关闭线程池 */ private void closeThreadPool(final ExecutorService executor) { try { threadCompletedCounter.await(); executor.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { // mock List<WeiboPerson> weiboPersonList = new ArrayList<WeiboPerson>(); int i = 1; while (i <= 10) { WeiboPerson weiboPerson = new WeiboPerson(); weiboPerson.setName("a" + i); weiboPersonList.add(weiboPerson); i++; } // test multi-thread BaiduBaikeJob baiduBaikeJob = new BaiduBaikeJob(); baiduBaikeJob.baiduBaikeRunInMultiThreads(weiboPersonList); } } |
from:http://blog.csdn.net/textboy/article/details/44680289
View Details